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

@ -7,6 +7,9 @@ such sensors and known workarounds if they exist.
#### Grove Sensors
* **RN2903** Click 2 version. This device will not work using the
Edison UART on the Arduino breakout. It does work on Edison using a
USB->serial interface.
* **Grove LCD RGB Backlit** (JHD1313M1) requires 5V and should be used with an
external power supply connected to the board to function properly. Although
some high powered USB ports might be enough, in most cases you will encounter

View File

@ -0,0 +1,122 @@
/*
* 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 <unistd.h>
#include <iostream>
#include <sstream>
#include <string>
#include <signal.h>
#include "rn2903.hpp"
#include "upm_utilities.h"
using namespace std;
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
string defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
cout << "Using device: " << defaultDev << endl;
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
upm::RN2903 sensor = upm::RN2903(defaultDev,
RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// upm::RN2903 sensor = upm::RN2903(0, RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
cout << "Failed to retrieve device version string" << endl;
return 1;
}
cout << "Firmware version: " << sensor.getResponse() << endl;
cout << "Hardware EUI: " << sensor.getHardwareEUI() << endl;
// For this example, we will just try to receive a packet
// transmitted by the p2p-tx rn2903 example. We reset the
// device to defaults, and we do not make any adjustments to the
// radio configuration. You will probably want to do so for a
// real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// We will use continuous mode (window_size 0), though the default
// radio watch dog timer will expire every 15 seconds. We will
// just loop here.
while (shouldRun)
{
cout << "Waiting for packet..." << endl;
RN2903_RESPONSE_T rv;
rv = sensor.radioRx(0);
if (rv)
{
cout << "radioRx() failed with code " << int(rv) << endl;
}
else
{
string resp = sensor.getResponse();
string payload = sensor.getRadioRxPayload();
if (!payload.size())
cout << "Got response: '" << resp << "'" << endl;
else
cout <<"Got payload: '"
<< sensor.fromHex(payload)
<< "'"
<< endl;
}
cout << endl;
}
cout << "Exiting" << endl;
//! [Interesting]
return 0;
}

View File

@ -0,0 +1,126 @@
/*
* 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 <unistd.h>
#include <iostream>
#include <sstream>
#include <string>
#include <signal.h>
#include "rn2903.hpp"
#include "upm_utilities.h"
using namespace std;
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
string defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
cout << "Using device: " << defaultDev << endl;
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
upm::RN2903 sensor = upm::RN2903(defaultDev,
RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// upm::RN2903 sensor = upm::RN2903(0, RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
cout << "Failed to retrieve device version string" << endl;
return 1;
}
cout << "Firmware version: " << sensor.getResponse() << endl;
cout << "Hardware EUI: " << sensor.getHardwareEUI() << endl;
// For this example, we will just try transmitting a packet over
// LoRa. We reset the device to defaults, and we do not make any
// adjustments to the radio configuration. You will probably want
// to do so for a real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// the default radio watchdog timer is set for 15 seconds, so we
// will send a packet every 10 seconds. In reality, local
// restrictions limit the amount of time on the air, so in a real
// implementation, you would not want to send packets that
// frequently.
int count = 0;
while (shouldRun)
{
ostringstream output;
output << "Ping " << count++;
// All payloads must be hex encoded
string payload = sensor.toHex(output.str());
cout << "Transmitting a packet, data: '"
<< output.str()
<< "' -> hex: '"
<< payload
<< "'"
<< endl;
RN2903_RESPONSE_T rv;
rv = sensor.radioTx(payload);
if (rv == RN2903_RESPONSE_OK)
cout << "Transmit successful." << endl;
else
cout << "Transmit failed with code " << int(rv) << endl;
cout << endl;
upm_delay(10);
}
cout << "Exiting" << endl;
//! [Interesting]
return 0;
}

137
examples/c++/rn2903.cxx Normal file
View File

@ -0,0 +1,137 @@
/*
* 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 <unistd.h>
#include <iostream>
#include <string>
#include "rn2903.hpp"
#include "upm_utilities.h"
using namespace std;
int main(int argc, char **argv)
{
//! [Interesting]
string defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
cout << "Using device: " << defaultDev << endl;
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
upm::RN2903 sensor = upm::RN2903(defaultDev,
RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// upm::RN2903 sensor = upm::RN2903(0, RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
cout << "Failed to retrieve device version string" << endl;
return 1;
}
cout << "Firmware version: " << sensor.getResponse() << endl;
cout << "Hardware EUI: " << sensor.getHardwareEUI() << endl;
// we can support two types of join, OTAA and ABP. Each requires
// that certain parameters be set first. We will only attempt ABP
// joining with this example since it's the only one that can
// succeed without actual configuration. In both cases, if you
// are actually attempting to join a real LoRaWAN network, you
// must change the parameters below to match the network you are
// attempting to join.
// For OTAA, you need to supply valid Device EUI, Application EUI,
// and Application key:
//
// sensor.setDeviceEUI("0011223344556677");
// sensor.setApplicationEUI("0011223344556677");
// sensor.setApplicationKey("01234567012345670123456701234567");
//
// RN2903_JOIN_STATUS_T rv = sensor.join(RN2903_JOIN_TYPE_OTAA);
// A successful join will return RN2903_JOIN_STATUS_ACCEPTED (0).
// cout << "JOIN: got rv " << int(rv) << endl;
// Try an ABP join. Note, these parameters are made up. For a
// real network, you will want to use the correct values
// obviously. For an ABP join, you need to supply the Device
// Address, Network Session Key, and the Application Session Key.
sensor.setDeviceAddr("00112233");
sensor.setNetworkSessionKey("00112233001122330011223300112233");
sensor.setApplicationSessionKey("00112233001122330011223300112233");
RN2903_JOIN_STATUS_T rv = sensor.join(RN2903_JOIN_TYPE_ABP);
if (rv == RN2903_JOIN_STATUS_ACCEPTED)
{
cout << "Join successful." << endl;
// All transmit payloads must be hex encoded strings, so
// pretend we have a temperature sensor that gave us a value
// of 25.6 C, and we want to transmit it.
string faketemp = "25.6";
cout << "Transmitting a packet..." << endl;
RN2903_MAC_TX_STATUS_T trv;
trv = sensor.macTx(RN2903_MAC_MSG_TYPE_UNCONFIRMED,
1, // port number
sensor.toHex(faketemp));
if (trv == RN2903_MAC_TX_STATUS_TX_OK)
cout << "Transmit successful." << endl;
else
{
// check to see if we got a downlink packet
if (trv == RN2903_MAC_TX_STATUS_RX_RECEIVED)
{
cout << "Transmit successful, downlink packet received: "
<< sensor.getResponse();
}
else
{
cout << "Transmit failed with code " << int(trv) << endl;
}
}
}
else
{
cout << "Join failed with code " << int(rv) << endl;
}
cout << "Exiting" << endl;
//! [Interesting]
return 0;
}

137
examples/c/rn2903-p2p-rx.c Normal file
View File

@ -0,0 +1,137 @@
/*
* 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 <unistd.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "rn2903.h"
#include "upm_utilities.h"
#include "upm_platform.h"
int shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
#if defined(UPM_PLATFORM_ZEPHYR) && !defined(CONFIG_STDOUT_CONSOLE)
# define printf printk
#endif
int main(int argc, char **argv)
{
//! [Interesting]
char *defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
printf("Using device: %s\n", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
#if defined(UPM_PLATFORM_ZEPHYR)
rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
#else
rn2903_context sensor = rn2903_init_tty(defaultDev,
RN2903_DEFAULT_BAUDRATE);
#endif
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
if (!sensor)
{
printf("rn2903_init_tty() failed.\n");
return 1;
}
// enable debugging
// rn2903_set_debug(sensor, true);
// get version
if (rn2903_command(sensor, "sys get ver"))
{
printf("Failed to retrieve device version string\n");
rn2903_close(sensor);
return 1;
}
printf("Firmware version: %s\n", rn2903_get_response(sensor));
printf("Hardware EUI: %s\n", rn2903_get_hardware_eui(sensor));
// For this example, we will just try to receive a packet
// transmitted by the p2p-tx rn2903 example. We reset the
// device to defaults, and we do not make any adjustments to the
// radio configuration. You will probably want to do so for a
// real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
if (rn2903_mac_pause(sensor))
{
printf("Failed to pause the LoRaWAN stack\n");
rn2903_close(sensor);
return 1;
}
// We will use continuous mode (window_size 0), though the default
// radio watch dog timer will expire every 15 seconds. We will
// just loop here.
while (shouldRun)
{
printf("Waiting for packet...\n");
RN2903_RESPONSE_T rv;
rv = rn2903_radio_rx(sensor, 0);
if (rv)
{
printf("rn2903_radio_rx() failed with code (%d)\n", rv);
}
else
{
const char *resp = rn2903_get_response(sensor);
const char *payload = rn2903_get_radio_rx_payload(sensor);
if (!payload)
printf("Got response: '%s'\n", resp);
else
printf("Got payload: '%s'\n",
rn2903_from_hex(sensor, payload));
}
printf("\n");
}
printf("Exiting\n");
rn2903_close(sensor);
//! [Interesting]
return 0;
}

139
examples/c/rn2903-p2p-tx.c Normal file
View File

@ -0,0 +1,139 @@
/*
* 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 <unistd.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "rn2903.h"
#include "upm_utilities.h"
#include "upm_platform.h"
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
#if defined(UPM_PLATFORM_ZEPHYR) && !defined(CONFIG_STDOUT_CONSOLE)
# define printf printk
#endif
int main(int argc, char **argv)
{
//! [Interesting]
char *defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
printf("Using device: %s\n", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
#if defined(UPM_PLATFORM_ZEPHYR)
rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
#else
rn2903_context sensor = rn2903_init_tty(defaultDev,
RN2903_DEFAULT_BAUDRATE);
#endif
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
if (!sensor)
{
printf("rn2903_init_tty() failed.\n");
return 1;
}
// enable debugging
// rn2903_set_debug(sensor, true);
// get version
if (rn2903_command(sensor, "sys get ver"))
{
printf("Failed to retrieve device version string\n");
rn2903_close(sensor);
return 1;
}
printf("Firmware version: %s\n", rn2903_get_response(sensor));
printf("Hardware EUI: %s\n", rn2903_get_hardware_eui(sensor));
// For this example, we will just try transmitting a packet over
// LoRa. We reset the device to defaults, and we do not make any
// adjustments to the radio configuration. You will probably want
// to do so for a real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
if (rn2903_mac_pause(sensor))
{
printf("Failed to pause the LoRaWAN stack\n");
rn2903_close(sensor);
return 1;
}
// the default radio watchdog timer is set for 15 seconds, so we
// will send a packet every 10 seconds. In reality, local
// restrictions limit the amount of time on the air, so in a real
// implementation, you would not want to send packets that
// frequently.
int count = 0;
while (shouldRun)
{
char pingbuf[32] = {};
snprintf(pingbuf, 32, "Ping %d", count++);
// All payloads must be hex encoded
const char *payload = rn2903_to_hex(sensor, pingbuf, strlen(pingbuf));
printf("Transmitting a packet, data: '%s' -> hex: '%s'\n",
pingbuf, payload);
RN2903_RESPONSE_T rv;
rv = rn2903_radio_tx(sensor, payload);
if (rv == RN2903_RESPONSE_OK)
printf("Transmit successful.\n");
else
printf("Transmit failed with code %d.\n", rv);
printf("\n");
upm_delay(10);
}
printf("Exiting\n");
rn2903_close(sensor);
//! [Interesting]
return 0;
}

153
examples/c/rn2903.c Normal file
View File

@ -0,0 +1,153 @@
/*
* 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 <unistd.h>
#include <stdio.h>
#include <string.h>
#include "rn2903.h"
#include "upm_utilities.h"
#include "upm_platform.h"
#if defined(UPM_PLATFORM_ZEPHYR) && !defined(CONFIG_STDOUT_CONSOLE)
# define printf printk
#endif
int main(int argc, char **argv)
{
//! [Interesting]
char *defaultDev = "/dev/ttyUSB0";
if (argc > 1)
defaultDev = argv[1];
printf("Using device: %s\n", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
#if defined(UPM_PLATFORM_ZEPHYR)
rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
#else
rn2903_context sensor = rn2903_init_tty(defaultDev,
RN2903_DEFAULT_BAUDRATE);
#endif
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// rn2903_context sensor = rn2903_init(0, RN2903_DEFAULT_BAUDRATE);
if (!sensor)
{
printf("rn2903_init_tty() failed.\n");
return 1;
}
// enable debugging
// rn2903_set_debug(sensor, true);
// get version
if (rn2903_command(sensor, "sys get ver"))
{
printf("Failed to retrieve device version string\n");
rn2903_close(sensor);
return 1;
}
printf("Firmware version: %s\n", rn2903_get_response(sensor));
printf("Hardware EUI: %s\n", rn2903_get_hardware_eui(sensor));
// we can support two types of join, OTAA and ABP. Each requires
// that certain parameters be set first. We will only attempt ABP
// joining with this example since it's the only one that can
// succeed without actual configuration. In both cases, if you
// are actually attempting to join a real LoRaWAN network, you
// must change the parameters below to match the network you are
// attempting to join.
// For OTAA, you need to supply valid Device EUI, Application EUI,
// and Application key:
//
// rn2903_set_device_eui(sensor, "0011223344556677");
// rn2903_set_application_eui(sensor, "0011223344556677");
// rn2903_set_application_key(sensor, "01234567012345670123456701234567");
//
// RN2903_JOIN_STATUS_T rv = rn2903_join(sensor, RN2903_JOIN_TYPE_OTAA);
// A successful join will return RN2903_JOIN_STATUS_ACCEPTED (0).
// printf("JOIN: got rv %d\n", rv);
// Try an ABP join. Note, these parameters are made up. For a
// real network, you will want to use the correct values
// obviously. For an ABP join, you need to supply the Device
// Address, Network Session Key, and the Application Session Key.
rn2903_set_device_addr(sensor, "00112233");
rn2903_set_network_session_key(sensor, "00112233001122330011223300112233");
rn2903_set_application_session_key(sensor,
"00112233001122330011223300112233");
RN2903_JOIN_STATUS_T rv = rn2903_join(sensor, RN2903_JOIN_TYPE_ABP);
if (rv == RN2903_JOIN_STATUS_ACCEPTED)
{
printf("Join successful.\n");
// All transmit payloads must be hex encoded strings, so
// pretend we have a temperature sensor that gave us a value
// of 25.6 C, and we want to transmit it.
const char *faketemp = "25.6";
printf("Transmitting a packet....\n");
RN2903_MAC_TX_STATUS_T trv;
trv = rn2903_mac_tx(sensor, RN2903_MAC_MSG_TYPE_UNCONFIRMED,
1, // port number
rn2903_to_hex(sensor, faketemp, strlen(faketemp)));
if (trv == RN2903_MAC_TX_STATUS_TX_OK)
printf("Transmit successful.\n");
else
{
// check to see if we got a downlink packet
if (trv == RN2903_MAC_TX_STATUS_RX_RECEIVED)
{
printf("Transmit successful, downlink packet received: %s\n",
rn2903_get_response(sensor));
}
else
{
printf("Transmit failed with code %d.\n", trv);
}
}
}
else
{
printf("Join failed with code %d.\n", rv);
}
printf("Exiting\n");
rn2903_close(sensor);
//! [Interesting]
return 0;
}

View File

@ -189,6 +189,7 @@ add_example(BMM150_Example bmm150)
add_example(LSM303AGR_Example lsm303agr)
add_example(LSM303D_Example lsm303d)
add_example(VEML6070Sample veml6070)
add_example(RN2903_Example rn2903)
add_example_with_path(Jhd1313m1_lcdSample jhd1313m1 jhd1313m1)
add_example_with_path(Jhd1313m1Sample jhd1313m1 jhd1313m1)
@ -215,3 +216,5 @@ add_example_with_path(NMEAGPS_I2C_Example nmea_gps nmea_gps)
add_example_with_path(MCP2515_TXRX_Example mcp2515 mcp2515)
add_example_with_path(LE910_Example uartat uartat)
add_example_with_path(SpeakerPWMSample speaker speaker)
add_example_with_path(RN2903_P2P_RX_Example rn2903 rn2903)
add_example_with_path(RN2903_P2P_TX_Example rn2903 rn2903)

View File

@ -0,0 +1,138 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* The MIT License
*
* 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.
*/
import upm_rn2903.*;
public class RN2903_Example
{
private static String defaultDev = "/dev/ttyUSB0";
public static void main(String[] args) throws InterruptedException
{
// ! [Interesting]
if (args.length > 0)
defaultDev = args[0];
System.out.println("Using device " + defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
RN2903 sensor = new RN2903(defaultDev,
javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// RN2903 sensor = new RN2903(defaultDev,
// upm_rn2903.javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver")
!= RN2903_RESPONSE_T.RN2903_RESPONSE_OK)
{
System.out.println("Failed to retrieve device version string");
System.exit(1);
}
System.out.println("Firmware version: " + sensor.getResponse());
System.out.println("Hardware EUI: " + sensor.getHardwareEUI());
// we can support two types of join, OTAA and ABP. Each requires
// that certain parameters be set first. We will only attempt ABP
// joining with this example since it's the only one that can
// succeed without actual configuration. In both cases, if you
// are actually attempting to join a real LoRaWAN network, you
// must change the parameters below to match the network you are
// attempting to join.
// For OTAA, you need to supply valid Device EUI, Application EUI,
// and Application key:
//
// sensor.setDeviceEUI("0011223344556677");
// sensor.setApplicationEUI("0011223344556677");
// sensor.setApplicationKey("01234567012345670123456701234567");
//
// RN2903_JOIN_STATUS_T rv = sensor.join(RN2903_JOIN_TYPE_OTAA);
// A successful join will return RN2903_JOIN_STATUS_ACCEPTED (0).
// cout << "JOIN: got rv " << int(rv) << endl;
// Try an ABP join. Note, these parameters are made up. For a
// real network, you will want to use the correct values
// obviously. For an ABP join, you need to supply the Device
// Address, Network Session Key, and the Application Session Key.
sensor.setDeviceAddr("00112233");
sensor.setNetworkSessionKey("00112233001122330011223300112233");
sensor.setApplicationSessionKey("00112233001122330011223300112233");
RN2903_JOIN_STATUS_T rv =
sensor.join(RN2903_JOIN_TYPE_T.RN2903_JOIN_TYPE_ABP);
if (rv == RN2903_JOIN_STATUS_T.RN2903_JOIN_STATUS_ACCEPTED)
{
System.out.println("Join successful.");
// All transmit payloads must be hex encoded strings, so
// pretend we have a temperature sensor that gave us a value
// of 25.6 C, and we want to transmit it.
String faketemp = "25.6";
System.out.println("Transmitting a packet...");
RN2903_MAC_TX_STATUS_T trv =
sensor.macTx(RN2903_MAC_MSG_TYPE_T.RN2903_MAC_MSG_TYPE_UNCONFIRMED,
1, // port number
sensor.toHex(faketemp));
if (trv == RN2903_MAC_TX_STATUS_T.RN2903_MAC_TX_STATUS_TX_OK)
System.out.println("Transmit successful.");
else
{
// check to see if we got a downlink packet
if (trv == RN2903_MAC_TX_STATUS_T.RN2903_MAC_TX_STATUS_RX_RECEIVED)
{
System.out.println("Transmit successful, downlink packet received: "
+ sensor.getResponse());
}
else
{
System.out.println("Transmit failed with code " + trv);
}
}
}
else
{
System.out.println("Join failed with code " + rv);
}
System.out.println("Exiting...");
// ! [Interesting]
}
}

View File

@ -0,0 +1,106 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* The MIT License
*
* 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.
*/
import upm_rn2903.*;
public class RN2903_P2P_RX_Example
{
private static String defaultDev = "/dev/ttyUSB0";
public static void main(String[] args) throws InterruptedException
{
// ! [Interesting]
if (args.length > 0)
defaultDev = args[0];
System.out.println("Using device " + defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
RN2903 sensor = new RN2903(defaultDev,
javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// RN2903 sensor = new RN2903(defaultDev,
// upm_rn2903.javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver")
!= RN2903_RESPONSE_T.RN2903_RESPONSE_OK)
{
System.out.println("Failed to retrieve device version string");
System.exit(1);
}
System.out.println("Firmware version: " + sensor.getResponse());
System.out.println("Hardware EUI: " + sensor.getHardwareEUI());
// For this example, we will just try to receive a packet
// transmitted by the p2p-tx rn2903 example. We reset the
// device to defaults, and we do not make any adjustments to the
// radio configuration. You will probably want to do so for a
// real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// We will use continuous mode (window_size 0), though the default
// radio watch dog timer will expire every 15 seconds. We will
// just loop here.
while (true)
{
System.out.println("Waiting for packet...");
RN2903_RESPONSE_T rv = sensor.radioRx(0);
if (rv != RN2903_RESPONSE_T.RN2903_RESPONSE_OK)
{
System.out.println("radioRx() failed with code "
+ rv.toString());
}
else
{
String resp = sensor.getResponse();
String payload = sensor.getRadioRxPayload();
if (payload.length() == 0)
System.out.println("Got response: '" + resp + "'");
else
System.out.println("Got payload: '"
+ sensor.fromHex(payload)
+ "'");
}
System.out.println();
}
// ! [Interesting]
}
}

View File

@ -0,0 +1,111 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* The MIT License
*
* 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.
*/
import upm_rn2903.*;
public class RN2903_P2P_TX_Example
{
private static String defaultDev = "/dev/ttyUSB0";
public static void main(String[] args) throws InterruptedException
{
// ! [Interesting]
if (args.length > 0)
defaultDev = args[0];
System.out.println("Using device " + defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
RN2903 sensor = new RN2903(defaultDev,
javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// RN2903 sensor = new RN2903(defaultDev,
// upm_rn2903.javaupm_rn2903.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver")
!= RN2903_RESPONSE_T.RN2903_RESPONSE_OK)
{
System.out.println("Failed to retrieve device version string");
System.exit(1);
}
System.out.println("Firmware version: " + sensor.getResponse());
System.out.println("Hardware EUI: " + sensor.getHardwareEUI());
// For this example, we will just try transmitting a packet over
// LoRa. We reset the device to defaults, and we do not make any
// adjustments to the radio configuration. You will probably want
// to do so for a real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// the default radio watchdog timer is set for 15 seconds, so we
// will send a packet every 10 seconds. In reality, local
// restrictions limit the amount of time on the air, so in a real
// implementation, you would not want to send packets that
// frequently.
Integer count = 0;
while (true)
{
String output = "Ping " + count.toString();
count++;
// All payloads must be hex encoded
String payload = sensor.toHex(output);
System.out.println("Transmitting a packet, data: '"
+ output
+ "' -> hex: '"
+ payload
+ "'");
RN2903_RESPONSE_T rv = sensor.radioTx(payload);
if (rv == RN2903_RESPONSE_T.RN2903_RESPONSE_OK)
System.out.println("Transmit successful.");
else
System.out.println("Transmit failed with code "
+ rv.toString());
System.out.println();
Thread.sleep(10000);
}
// ! [Interesting]
}
}

View File

@ -0,0 +1,103 @@
/*
* 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.
*/
var sensorObj = require('jsupm_rn2903');
var defaultDev = "/dev/ttyUSB0";
// if an argument was specified, use it as the device instead
if (process.argv.length > 2)
{
defaultDev = process.argv[2];
}
console.log("Using device:", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
var sensor = new sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// var sensor = new sensorObj.RN2903(0,
// sensorObj.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
console.log("Failed to retrieve device version string");
process.exit(1);
}
console.log("Firmware version: " + sensor.getResponse());
console.log("Hardware EUI: " + sensor.getHardwareEUI());
// For this example, we will just try to receive a packet
// transmitted by the p2p-tx rn2903 example. We reset the
// device to defaults, and we do not make any adjustments to the
// radio configuration. You will probably want to do so for a
// real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// We will use continuous mode (window_size 0), though the default
// radio watch dog timer will expire every 15 seconds. We will
// just loop here.
while (true)
{
console.log("Waiting for packet...");
var rv = sensor.radioRx(0);
if (rv)
{
console.log("radioRx() failed with code " + rv);
}
else
{
var resp = sensor.getResponse();
var payload = sensor.getRadioRxPayload();
if (!payload.length)
console.log("Got response: '" + resp + "'");
else
console.log("Got payload: '"
+ sensor.fromHex(payload)
+ "'");
}
console.log();
}
process.on('SIGINT', function() {
sensor = null;
sensorObj.cleanUp();
sensorObj = null;
console.log("Exiting...");
process.exit(0);
});

View File

@ -0,0 +1,108 @@
/*
* 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.
*/
var sensorObj = require('jsupm_rn2903');
var defaultDev = "/dev/ttyUSB0";
// if an argument was specified, use it as the device instead
if (process.argv.length > 2)
{
defaultDev = process.argv[2];
}
console.log("Using device:", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
var sensor = new sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// var sensor = new sensorObj.RN2903(0,
// sensorObj.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
console.log("Failed to retrieve device version string");
process.exit(1);
}
console.log("Firmware version: " + sensor.getResponse());
console.log("Hardware EUI: " + sensor.getHardwareEUI());
// For this example, we will just try transmitting a packet over
// LoRa. We reset the device to defaults, and we do not make any
// adjustments to the radio configuration. You will probably want
// to do so for a real life application.
// The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
// the default radio watchdog timer is set for 15 seconds, so we
// will send a packet every 10 seconds. In reality, local
// restrictions limit the amount of time on the air, so in a real
// implementation, you would not want to send packets that
// frequently.
var count = 0;
function transmit()
{
var output = "Ping " + count;
count++;
// All payloads must be hex encoded
var payload = sensor.toHex(output);
console.log("Transmitting a packet, data: '"
+ output
+ "' -> hex: '"
+ payload
+ "'");
var rv = sensor.radioTx(payload);
if (rv == sensorObj.RN2903_RESPONSE_OK)
console.log("Transmit successful.");
else
console.log("Transmit failed with code " + rv);
console.log();
}
setInterval(transmit, 10000);
process.on('SIGINT', function() {
sensor = null;
sensorObj.cleanUp();
sensorObj = null;
console.log("Exiting...");
process.exit(0);
});

View File

@ -0,0 +1,131 @@
/*
* 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.
*/
var sensorObj = require('jsupm_rn2903');
var defaultDev = "/dev/ttyUSB0";
// if an argument was specified, use it as the device instead
if (process.argv.length > 2)
{
defaultDev = process.argv[2];
}
console.log("Using device:", defaultDev);
// Instantiate a RN2903 sensor on defaultDev at 57600 baud.
var sensor = new sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE);
// To use an internal UART understood by MRAA, use the following
// to inititialize rather than the above, which by default uses a
// tty path.
//
// var sensor = new sensorObj.RN2903(0,
// sensorObj.RN2903_DEFAULT_BAUDRATE);
// enable debugging
// sensor.setDebug(true);
// get version
if (sensor.command("sys get ver"))
{
console.log("Failed to retrieve device version string");
process.exit(1);
}
console.log("Firmware version: " + sensor.getResponse());
console.log("Hardware EUI: " + sensor.getHardwareEUI());
// we can support two types of join, OTAA and ABP. Each requires
// that certain parameters be set first. We will only attempt ABP
// joining with this example since it's the only one that can
// succeed without actual configuration. In both cases, if you
// are actually attempting to join a real LoRaWAN network, you
// must change the parameters below to match the network you are
// attempting to join.
// For OTAA, you need to supply valid Device EUI, Application EUI,
// and Application key:
//
// sensor.setDeviceEUI("0011223344556677");
// sensor.setApplicationEUI("0011223344556677");
// sensor.setApplicationKey("01234567012345670123456701234567");
//
// RN2903_JOIN_STATUS_T rv = sensor.join(RN2903_JOIN_TYPE_OTAA);
// A successful join will return RN2903_JOIN_STATUS_ACCEPTED (0).
// cout << "JOIN: got rv " << int(rv) << endl;
// Try an ABP join. Note, these parameters are made up. For a
// real network, you will want to use the correct values
// obviously. For an ABP join, you need to supply the Device
// Address, Network Session Key, and the Application Session Key.
sensor.setDeviceAddr("00112233");
sensor.setNetworkSessionKey("00112233001122330011223300112233");
sensor.setApplicationSessionKey("00112233001122330011223300112233");
var rv = sensor.join(sensorObj.RN2903_JOIN_TYPE_ABP);
if (rv == sensorObj.RN2903_JOIN_STATUS_ACCEPTED)
{
console.log("Join successful.");
// All transmit payloads must be hex encoded strings, so
// pretend we have a temperature sensor that gave us a value
// of 25.6 C, and we want to transmit it.
var faketemp = "25.6";
console.log("Transmitting a packet...");
var trv = sensor.macTx(sensorObj.RN2903_MAC_MSG_TYPE_UNCONFIRMED,
1, // port number
sensor.toHex(faketemp));
if (trv == sensorObj.RN2903_MAC_TX_STATUS_TX_OK)
console.log("Transmit successful.");
else
{
// check to see if we got a downlink packet
if (trv == sensorObj.RN2903_MAC_TX_STATUS_RX_RECEIVED)
{
console.log("Transmit successful, downlink packet received: "
+ sensor.getResponse());
}
else
{
console.log("Transmit failed with code " + trv);
}
}
}
else
{
console.log("Join failed with code " + rv);
}
console.log("Exiting");
sensor = null;
sensorObj.cleanUp();
sensorObj = null;
process.exit(0);

108
examples/python/rn2903-p2p-rx.py Executable file
View File

@ -0,0 +1,108 @@
#!/usr/bin/python
# Author: Jon Trulson <jtrulson@ics.com>
# Copyright (c) 2017 Intel Corporation.
#
# The MIT License
#
# 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.
from __future__ import print_function
import time, sys, signal, atexit
from upm import pyupm_rn2903 as sensorObj
def main():
## Exit handlers ##
# This function stops python from printing a stacktrace when you
# hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This function lets you run code on exit
def exitHandler():
print("Exiting")
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
defaultDev = "/dev/ttyUSB0"
if (len(sys.argv) > 1):
defaultDev = sys.argv[1]
print("Using device", defaultDev)
# Instantiate a RN2903 sensor on defaultDev at 57600 baud.
sensor = sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE)
# To use an internal UART understood by MRAA, use the following
# to inititialize rather than the above, which by default uses a
# tty path.
#
# sensor = sensorObj.RN2903(0,
# sensorObj.RN2903_DEFAULT_BAUDRATE)
# enable debugging
# sensor.setDebug(True)
# get version
if (sensor.command("sys get ver")):
print("Failed to retrieve device version string")
sys.exit(1)
print("Firmware version: " + sensor.getResponse())
print("Hardware EUI: " + sensor.getHardwareEUI())
# For this example, we will just try to receive a packet
# transmitted by the p2p-tx rn2903 example. We reset the
# device to defaults, and we do not make any adjustments to the
# radio configuration. You will probably want to do so for a
# real life application.
# The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
# We will use continuous mode (window_size 0), though the default
# radio watch dog timer will expire every 15 seconds. We will
# just loop here.
while (True):
print("Waiting for packet...")
rv = sensor.radioRx(0);
if (rv):
print("radioRx() failed with code " + str(rv))
else:
resp = sensor.getResponse();
payload = sensor.getRadioRxPayload();
if (not len(payload)):
print("Got response: '", end='')
print(resp, end="")
print("'")
else:
print("Got payload: '", end='')
print(sensor.fromHex(payload), end='')
print("'")
print()
if __name__ == '__main__':
main()

114
examples/python/rn2903-p2p-tx.py Executable file
View File

@ -0,0 +1,114 @@
#!/usr/bin/python
# Author: Jon Trulson <jtrulson@ics.com>
# Copyright (c) 2017 Intel Corporation.
#
# The MIT License
#
# 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.
from __future__ import print_function
import time, sys, signal, atexit
from upm import pyupm_rn2903 as sensorObj
def main():
## Exit handlers ##
# This function stops python from printing a stacktrace when you
# hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This function lets you run code on exit
def exitHandler():
print("Exiting")
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
defaultDev = "/dev/ttyUSB0"
if (len(sys.argv) > 1):
defaultDev = sys.argv[1]
print("Using device", defaultDev)
# Instantiate a RN2903 sensor on defaultDev at 57600 baud.
sensor = sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE)
# To use an internal UART understood by MRAA, use the following
# to inititialize rather than the above, which by default uses a
# tty path.
#
# sensor = sensorObj.RN2903(0,
# sensorObj.RN2903_DEFAULT_BAUDRATE)
# enable debugging
# sensor.setDebug(True)
# get version
if (sensor.command("sys get ver")):
print("Failed to retrieve device version string")
sys.exit(1)
print("Firmware version: " + sensor.getResponse())
print("Hardware EUI: " + sensor.getHardwareEUI())
# For this example, we will just try transmitting a packet over
# LoRa. We reset the device to defaults, and we do not make any
# adjustments to the radio configuration. You will probably want
# to do so for a real life application.
# The first thing to do is to suspend the LoRaWAN stack on the device.
sensor.macPause();
# the default radio watchdog timer is set for 15 seconds, so we
# will send a packet every 10 seconds. In reality, local
# restrictions limit the amount of time on the air, so in a real
# implementation, you would not want to send packets that
# frequently.
count = 0;
while (True):
output = "Ping " + str(count)
count += 1
# All payloads must be hex encoded
payload = sensor.toHex(output);
print("Transmitting a packet, data: '", end='')
print(output, end='')
print("' -> hex: '", end='')
print(payload, end='')
print("'")
rv = sensor.radioTx(payload);
if (rv == sensorObj.RN2903_RESPONSE_OK):
print("Transmit successful.")
else:
print("Transmit failed with code " + str(rv))
print()
time.sleep(10)
if __name__ == '__main__':
main()

129
examples/python/rn2903.py Executable file
View File

@ -0,0 +1,129 @@
#!/usr/bin/python
# Author: Jon Trulson <jtrulson@ics.com>
# Copyright (c) 2017 Intel Corporation.
#
# The MIT License
#
# 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.
from __future__ import print_function
import time, sys, signal, atexit
from upm import pyupm_rn2903 as sensorObj
def main():
## Exit handlers ##
# This function stops python from printing a stacktrace when you
# hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This function lets you run code on exit
def exitHandler():
print("Exiting")
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
defaultDev = "/dev/ttyUSB0"
if (len(sys.argv) > 1):
defaultDev = sys.argv[1]
print("Using device", defaultDev)
# Instantiate a RN2903 sensor on defaultDev at 57600 baud.
sensor = sensorObj.RN2903(defaultDev,
sensorObj.RN2903_DEFAULT_BAUDRATE)
# To use an internal UART understood by MRAA, use the following
# to inititialize rather than the above, which by default uses a
# tty path.
#
# sensor = sensorObj.RN2903(0,
# sensorObj.RN2903_DEFAULT_BAUDRATE)
# enable debugging
# sensor.setDebug(True)
# get version
if (sensor.command("sys get ver")):
print("Failed to retrieve device version string")
sys.exit(1)
print("Firmware version: " + sensor.getResponse())
print("Hardware EUI: " + sensor.getHardwareEUI())
# we can support two types of join, OTAA and ABP. Each requires
# that certain parameters be set first. We will only attempt ABP
# joining with this example since it's the only one that can
# succeed without actual configuration. In both cases, if you
# are actually attempting to join a real LoRaWAN network, you
# must change the parameters below to match the network you are
# attempting to join.
# For OTAA, you need to supply valid Device EUI, Application EUI,
# and Application key:
#
# sensor.setDeviceEUI("0011223344556677")
# sensor.setApplicationEUI("0011223344556677")
# sensor.setApplicationKey("01234567012345670123456701234567")
#
# rv = sensor.join(RN2903_JOIN_TYPE_OTAA)
# A successful join will return RN2903_JOIN_STATUS_ACCEPTED (0).
# Try an ABP join. Note, these parameters are made up. For a
# real network, you will want to use the correct values
# obviously. For an ABP join, you need to supply the Device
# Address, Network Session Key, and the Application Session Key.
sensor.setDeviceAddr("00112233")
sensor.setNetworkSessionKey("00112233001122330011223300112233")
sensor.setApplicationSessionKey("00112233001122330011223300112233")
rv = sensor.join(sensorObj.RN2903_JOIN_TYPE_ABP)
if (rv == sensorObj.RN2903_JOIN_STATUS_ACCEPTED):
print("Join successful.")
# All transmit payloads must be hex encoded strings, so
# pretend we have a temperature sensor that gave us a value
# of 25.6 C, and we want to transmit it.
faketemp = "25.6"
print("Transmitting a packet...")
trv = sensor.macTx(sensorObj.RN2903_MAC_MSG_TYPE_UNCONFIRMED,
1, # port number
sensor.toHex(faketemp))
if (trv == sensorObj.RN2903_MAC_TX_STATUS_TX_OK):
print("Transmit successful.")
else:
# check to see if we got a downlink packet
if (trv == sensor.Obj.RN2903_MAC_TX_STATUS_RX_RECEIVED):
print("Transmit successful, downlink packet received:", end=' ')
print(sensor.getResponse())
else:
print("Transmit failed with code " + str(trv))
else:
print("Join failed with code " + str(rv))
if __name__ == '__main__':
main()

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