Files
M5Stack/src/LoRaWan.cpp
T
Björn Amann 7af7b6f7de Fix buffer overflow. (#206)
In C strings are 0-terminated, meaning that after the call to sprintf the char contains { 'a', 'b', '\0' }. This is an array of 3 chars we only reserver memory for 2.
2020-04-08 10:01:52 +08:00

1046 lines
26 KiB
C++

/*
LoRaWAN.cpp for M5Stack (fork from https://github.com/toddkrein/OTAA-LoRaWAN-Seeed)
2013 Copyright (c) Seeed Technology Inc. All right reserved.
2017 Copyright (c) Todd Krein. All rights reserved.
Original Author: Wayne Weng
Date: 2016-10-17
Greatly overhauled 2017 by Todd Krein (todd@krein.org)
The MIT License (MIT)
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.1 USA
*/
#include "LoRaWan.h"
const char *physTypeStr[10] = {"EU434", "EU868", "US915", "US915HYBRID", "AU915", "AS923", "CN470", "KR920", "CN470PREQUEL", "STE920"};
LoRaWanClass::LoRaWanClass(void)
{
memset(_buffer, 0, 256);
debug = false;
}
void LoRaWanClass::init(void)
{
Serial2.begin(9600, SERIAL_8N1, 16, 17);
// Serial2.begin(9600, SERIAL_8N1, 2, 5);
// SerialLoRa.begin(9600);
}
void LoRaWanClass::getVersion(char *buffer, short length, unsigned char timeout)
{
if(buffer)
{
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+VER=?\r\n");
readBuffer(buffer, length, timeout);
}
}
void LoRaWanClass::getId(char *buffer, short length, unsigned char timeout)
{
if(buffer)
{
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+ID=?\r\n");
readBuffer(buffer, length, timeout);
}
}
void LoRaWanClass::setId(char *DevAddr, char *DevEUI, char *AppEUI)
{
char cmd[64];
if(DevAddr)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+ID=DevAddr,\"%s\"\r\n", DevAddr);
sendCommand(cmd);
delay(DEFAULT_TIMEWAIT);
}
if(DevEUI)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+ID=DevEui,\"%s\"\r\n", DevEUI);
sendCommand(cmd);
delay(DEFAULT_TIMEWAIT);
}
if(AppEUI)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+ID=AppEui,\"%s\"\r\n", AppEUI);
sendCommand(cmd);
delay(DEFAULT_TIMEWAIT);
}
}
void LoRaWanClass::setKey(char *NwkSKey, char *AppSKey, char *AppKey)
{
char cmd[64];
if(NwkSKey)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+KEY=NWKSKEY,\"%s\"\r\n", NwkSKey);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
if(AppSKey)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+KEY=APPSKEY,\"%s\"\r\n", AppSKey);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
if(AppKey)
{
memset(cmd, 0, 64);
sprintf(cmd, "AT+KEY= APPKEY,\"%s\"\r\n", AppKey);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
}
bool LoRaWanClass::setDataRate(_data_rate_t dataRate, _physical_type_t physicalType)
{
char cmd[32];
// const char *str;
if ((physicalType <= UNINIT) && (physicalType >= UNDEF)) {
myType = UNINIT;
debugPrint("Unknown datarate\n");
return false;
}
myType = physicalType;
sendCommand(F("AT+DR="));
// str = (const char*)(physTypeStr[(int)myType]);
sendCommand(physTypeStr[myType]);
// sendCommand(str);
sendCommand(F("\r\n"));
// if(physicalType == EU434)sendCommand("AT+DR=EU433\r\n");
// else if(physicalType == EU868)sendCommand("AT+DR=EU868\r\n");
// else if(physicalType == US915)sendCommand("AT+DR=US915\r\n");
// else if(physicalType == AU920)sendCommand("AT+DR=AU920\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
memset(cmd, 0, 32);
sprintf(cmd, "AT+DR=%d\r\n", dataRate);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
return true;
}
void LoRaWanClass::setPower(short power)
{
char cmd[32];
memset(cmd, 0, 32);
sprintf(cmd, "AT+POWER=%d\r\n", power);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setPort(unsigned char port)
{
char cmd[32];
memset(cmd, 0, 32);
sprintf(cmd, "AT+PORT=%d\r\n", port);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setAdaptiveDataRate(bool command)
{
if(command)sendCommand("AT+ADR=ON\r\n");
else sendCommand("AT+ADR=OFF\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::getChannel(void)
{
sendCommand("AT+CH\r\n");
loraDebugPrint(DEFAULT_DEBUGTIME);
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setChannel(unsigned char channel, float frequency)
{
char cmd[32];
// if(channel > 16) channel = 16; // ??? this is wrong for US915
memset(cmd, 0, 32);
if (frequency == 0)
sprintf(cmd, "AT+CH=%d,0\r\n", channel);
else
sprintf(cmd, "AT+CH=%d,%d.%d\r\n", channel, (short)frequency, short(frequency * 10) % 10);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setChannel(unsigned char channel, float frequency, _data_rate_t dataRata)
{
char cmd[32];
if(channel > 16) channel = 16;
memset(cmd, 0, 32);
sprintf(cmd, "AT+CH=%d,%d.%d,%d\r\n", channel, (short)frequency, short(frequency * 10) % 10, dataRata);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setChannel(unsigned char channel, float frequency, _data_rate_t dataRataMin, _data_rate_t dataRataMax)
{
char cmd[32];
if(channel > 16) channel = 16;
memset(cmd, 0, 32);
sprintf(cmd, "AT+CH=%d,%d.%d,%d,%d\r\n", channel, (short)frequency, short(frequency * 10) % 10, dataRataMin, dataRataMax);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
bool LoRaWanClass::transferPacket(char *buffer, unsigned char timeout)
{
unsigned char length = strlen(buffer);
int count;
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+MSG=\"");
for(int i = 0; i < length; i ++)SerialLoRa.write(buffer[i]);
sendCommand("\"\r\n");
while (true) {
memset(_buffer, 0, BEFFER_LENGTH_MAX);
count = readLine(_buffer, BEFFER_LENGTH_MAX, timeout);
if (count == 0)
continue;
// handle timout!
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if (strstr(_buffer, "+MSG: Done"))
return true;
}
// memset(_buffer, 0, BEFFER_LENGTH_MAX);
// readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
//#if _DEBUG_SERIAL_
// SerialUSB.print(_buffer);
//#endif
// if(strstr(_buffer, "+MSG: Done"))return true;
// return false;
}
bool LoRaWanClass::transferPacket(unsigned char *buffer, unsigned char length, unsigned char timeout)
{
char temp[3] = {0};
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+MSGHEX=\"");
for(int i = 0; i < length; i ++)
{
sprintf(temp,"%02x", buffer[i]);
SerialLoRa.write(temp);
}
sendCommand("\"\r\n");
memset(_buffer, 0, BEFFER_LENGTH_MAX);
readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if(strstr(_buffer, "+MSGHEX: Done"))return true;
return false;
}
bool LoRaWanClass::transferPacketWithConfirmed(char *buffer, unsigned char timeout)
{
unsigned char length = strlen(buffer);
int i;
bool sentOK;
sentOK = false;
while(SerialLoRa.available())
SerialLoRa.read();
sendCommand("AT+CMSG=\"");
for(int i = 0; i < length; i ++)SerialLoRa.write(buffer[i]);
sendCommand("\"\r\n");
#ifdef deadcode
memset(_buffer, 0, BEFFER_LENGTH_MAX);
i = readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
_buffer[i] = 0;
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if(strstr(_buffer, "+CMSG: ACK Received"))
return true;
else
return false;
#endif
while (true) {
memset(_buffer, 0, BEFFER_LENGTH_MAX);
i = readLine(_buffer, BEFFER_LENGTH_MAX, timeout);
if (i == 0)
continue;
_buffer[i] = 0;
// !!! handle timeout
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if (strstr(_buffer, "+CMSG: Start"))
continue;
if (strstr(_buffer, "+CMSG: Wait ACK"))
continue;
if (strstr(_buffer, "+CMSG: TX"))
continue;
if (strstr(_buffer, "+CMSG: RXWIN"))
continue;
if (strstr(_buffer, "+CMSG: No free channel"))
break;
if (strstr(_buffer, "+CMSG: Done"))
break;
if (strstr(_buffer, "+CMSG: ACK Received")) {
sentOK = true;
continue;
}
SerialUSB.print("Result didn't match anything I expected.\n");
}
return sentOK;
}
bool LoRaWanClass::transferPacketWithConfirmed(unsigned char *buffer, unsigned char length, unsigned char timeout)
{
char temp[3] = {0};
int i;
unsigned char *ptr;
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+CMSGHEX=\"");
for(int i = 0; i < length; i ++)
{
sprintf(temp,"%02x", buffer[i]);
SerialLoRa.write(temp);
}
sendCommand("\"\r\n");
#if _DEBUG_SERIAL_
ptr = buffer;
for (i = 0; i < length; i++)
SerialUSB.print(*(ptr++));
SerialUSB.println("");
#endif
memset(_buffer, 0, BEFFER_LENGTH_MAX);
i = readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
_buffer[i] = 0;
SerialUSB.print(_buffer);
if(strstr(_buffer, "+CMSGHEX: ACK Received"))
return true;
else
return false;
}
short LoRaWanClass::receivePacket(char *buffer, short length, short *rssi)
{
char *ptr;
short number = 0;
ptr = strstr(_buffer, "RSSI ");
if(ptr)*rssi = atoi(ptr + 5);
else *rssi = -255;
ptr = strstr(_buffer, "RX: \"");
if(ptr)
{
ptr += 5;
for(short i = 0; ; i ++)
{
char temp[3] = {0, 0};
unsigned char tmp = '?', result = 0;
temp[0] = *(ptr + i * 3);
temp[1] = *(ptr + i * 3 + 1);
for(unsigned char j = 0; j < 2; j ++)
{
if((temp[j] >= '0') && (temp[j] <= '9'))
tmp = temp[j] - '0';
else if((temp[j] >= 'A') && (temp[j] <= 'F'))
tmp = temp[j] - 'A' + 10;
else if((temp[j] >= 'a') && (temp[j] <= 'f'))
tmp = temp[j] - 'a' + 10;
result = result * 16 + tmp;
}
if(i < length)buffer[i] = result;
if(*(ptr + i * 3 + 3) == '\"' && *(ptr + i * 3 + 4) == '\r' && *(ptr + i * 3 + 5) == '\n')
{
number = i + 1;
break;
}
}
}
ptr = strstr(_buffer, "MACCMD: \"");
if(ptr)
{
buffer[0] = 'M';
buffer[1] = 'A';
buffer[2] = 'C';
buffer[3] = 'C';
buffer[4] = 'M';
buffer[5] = 'D';
buffer[6] = ':';
ptr += 9;
for(short i = 0; ; i ++)
{
char temp[3] = {0};
unsigned char tmp = '?', result = 0;
temp[0] = *(ptr + i * 3);
temp[1] = *(ptr + i * 3 + 1);
for(unsigned char j = 0; j < 2; j ++)
{
if((temp[j] >= '0') && (temp[j] <= '9'))
tmp = temp[j] - '0';
else if((temp[j] >= 'A') && (temp[j] <= 'F'))
tmp = temp[j] - 'A' + 10;
else if((temp[j] >= 'a') && (temp[j] <= 'f'))
tmp = temp[j] - 'a' + 10;
result = result * 16 + tmp;
}
if((i + 7) < length)buffer[i + 7] = result;
if(*(ptr + i * 3 + 3) == '\"' && *(ptr + i * 3 + 4) == '\r' && *(ptr + i * 3 + 5) == '\n')
{
number = i + 1 + 7;
break;
}
}
}
memset(_buffer, 0, BEFFER_LENGTH_MAX);
return number;
}
bool LoRaWanClass::transferProprietaryPacket(char *buffer, unsigned char timeout)
{
unsigned char length = strlen(buffer);
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+PMSG=\"");
for(int i = 0; i < length; i ++)SerialLoRa.write(buffer[i]);
sendCommand("\"\r\n");
memset(_buffer, 0, BEFFER_LENGTH_MAX);
readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if(strstr(_buffer, "+PMSG: Done"))return true;
return false;
}
bool LoRaWanClass::transferProprietaryPacket(unsigned char *buffer, unsigned char length, unsigned char timeout)
{
char temp[3] = {0};
while(SerialLoRa.available())SerialLoRa.read();
sendCommand("AT+PMSGHEX=\"");
for(int i = 0; i < length; i ++)
{
sprintf(temp,"%02x", buffer[i]);
SerialLoRa.write(temp);
}
sendCommand("\"\r\n");
memset(_buffer, 0, BEFFER_LENGTH_MAX);
readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if(strstr(_buffer, "+PMSGHEX: Done"))return true;
return false;
}
void LoRaWanClass::setUnconfirmedMessageRepeatTime(unsigned char time)
{
char cmd[32];
if(time > 15) time = 15;
else if(time == 0) time = 1;
memset(cmd, 0, 32);
sprintf(cmd, "AT+REPT=%d\r\n", time);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setConfirmedMessageRetryTime(unsigned char time)
{
char cmd[32];
if(time > 15) time = 15;
else if(time == 0) time = 1;
memset(cmd, 0, 32);
sprintf(cmd, "AT+RETRY=%d\r\n", time);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::getReceiveWindowFirst(void)
{
sendCommand("AT+RXWIN1\r\n");
loraDebugPrint(DEFAULT_DEBUGTIME);
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setReceiveWindowFirst(bool command)
{
if(command)
sendCommand("AT+RXWIN1=ON\r\n");
else
sendCommand("AT+RXWIN1=OFF\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setReceiveWindowFirst(unsigned char channel, float frequency)
{
char cmd[32];
// if(channel > 16) channel = 16;
memset(cmd, 0, 32);
if (frequency == 0)
sprintf(cmd, "AT+RXWIN1=%d,0\r\n", channel);
else
sprintf(cmd, "AT+RXWIN1=%d,%d.%d\r\n", channel, (short)frequency, short(frequency * 10) % 10);
sendCommand(cmd);
SerialUSB.print(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME * 4); // this can have a lot of data to dump
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setReceiveWindowSecond(float frequency, _data_rate_t dataRate)
{
char cmd[32];
memset(cmd, 0, 32);
sprintf(cmd, "AT+RXWIN2=%d.%d,%d\r\n", (short)frequency, short(frequency * 10) % 10, dataRate);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setReceiveWindowSecond(float frequency, _spreading_factor_t spreadingFactor, _band_width_t bandwidth)
{
char cmd[32];
memset(cmd, 0, 32);
sprintf(cmd, "AT+RXWIN2=%d.%d,%d,%d\r\n", (short)frequency, short(frequency * 10) % 10, spreadingFactor, bandwidth);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setReceiveWindowDelay(_window_delay_t command, unsigned short _delay)
{
char cmd[32];
memset(cmd, 0, 32);
if(command == RECEIVE_DELAY1) sprintf(cmd, "AT+DELAY=RX1,%d\r\n", _delay);
else if(command == RECEIVE_DELAY2) sprintf(cmd, "AT+DELAY=RX2,%d\r\n", _delay);
else if(command == JOIN_ACCEPT_DELAY1) sprintf(cmd, "AT+DELAY=JRX1,%d\r\n", _delay);
else if(command == JOIN_ACCEPT_DELAY2) sprintf(cmd, "AT+DELAY=JRX2,%d\r\n", _delay);
sendCommand(cmd);
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::setClassType(_class_type_t type)
{
if(type == CLASS_A)sendCommand("AT+CLASS=A\r\n");
else if(type == CLASS_C)sendCommand("AT+CLASS=C\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
//
// set the JOIN mode to either LWOTAA or LWABP
// does a half-hearted attempt to check the results
//
bool LoRaWanClass::setDeviceMode(_device_mode_t mode)
{
char buffer[kLOCAL_BUFF_MAX];
int timeout = 1;
if(mode == LWABP)
sendCommand("AT+MODE=LWABP\r\n");
else if(mode == LWOTAA)
sendCommand("AT+MODE=LWOTAA\r\n");
else
return false;
memset(buffer, 0, kLOCAL_BUFF_MAX);
readBuffer(buffer, kLOCAL_BUFF_MAX - 1, timeout);
#if _DEBUG_SERIAL_
SerialUSB.print(buffer);
// loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
return strstr(buffer, "+MODE:"); // if it works, response is of form "+MODE: LWOTTA"
}
//
// JOIN with the application
//
// setDeviceMode should have been called before this.
bool LoRaWanClass::setOTAAJoin(_otaa_join_cmd_t command, unsigned char timeout)
{
// char *ptr;
short count;
bool joined = false;
if(command == JOIN)
sendCommand("AT+JOIN\r\n");
else if(command == FORCE)
sendCommand("AT+JOIN=FORCE\r\n");
else {
SerialUSB.print("Bad command to setOTAAJoin\n");
return false;
}
#if _DEBUG_SERIAL_
// loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
// delay(DEFAULT_TIMEWAIT);
while (true) {
memset(_buffer, 0, BEFFER_LENGTH_MAX);
count = readLine(_buffer, BEFFER_LENGTH_MAX, timeout);
if (count == 0)
continue;
// !!! handle timeout
#if _DEBUG_SERIAL_
SerialUSB.print(_buffer);
#endif
if (strstr(_buffer, "+JOIN: Join failed"))
continue;
if (strstr(_buffer, "+JOIN: LoRaWAN modem is busy"))
continue;
if (strstr(_buffer, "+JOIN: NORMAL"))
continue;
if (strstr(_buffer, "+JOIN: FORCE"))
continue;
if (strstr(_buffer, "+JOIN: Start"))
continue;
if (strstr(_buffer, "+JOIN: Done"))
break;
if (strstr(_buffer, "+JOIN: No free channel"))
break;
if (strstr(_buffer, "+JOIN: Network joined")) {
joined = true;
continue;
}
if (strstr(_buffer, "+JOIN: NetID")) {
joined = true;
continue;
}
SerialUSB.print("Result didn't match anything I expected.\n");
}
SerialUSB.print("Done with Join\n");
return joined;
}
void LoRaWanClass::setDeviceLowPower(void)
{
sendCommand("AT+LOWPOWER\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
//
// Reset the LoRa module. Does not factory reset
//
void LoRaWanClass::setDeviceReset(void)
{
sendCommand("AT+RESET\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
//
// Factory reset the module.
//
void LoRaWanClass::setDeviceDefault(void)
{
sendCommand("AT+FDEFAULT=RISINGHF\r\n");
#if _DEBUG_SERIAL_
loraDebugPrint(DEFAULT_DEBUGTIME);
#endif
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::initP2PMode(unsigned short frequency, _spreading_factor_t spreadingFactor, _band_width_t bandwidth,
unsigned char txPreamble, unsigned char rxPreamble, short power)
{
char cmd[64] = {0,};
sprintf(cmd, "AT+TEST=RFCFG,%d,%d,%d,%d,%d,%d\r\n", frequency, spreadingFactor, bandwidth, txPreamble, rxPreamble, power);
sendCommand("AT+MODE=TEST\r\n");
delay(DEFAULT_TIMEWAIT);
sendCommand(cmd);
delay(DEFAULT_TIMEWAIT);
sendCommand("AT+TEST=RXLRPKT\r\n");
delay(DEFAULT_TIMEWAIT);
}
void LoRaWanClass::transferPacketP2PMode(char *buffer)
{
unsigned char length = strlen(buffer);
sendCommand("AT+TEST=TXLRSTR,\"");
for(int i = 0; i < length; i ++)SerialLoRa.write(buffer[i]);
sendCommand("\"\r\n");
}
void LoRaWanClass::transferPacketP2PMode(unsigned char *buffer, unsigned char length)
{
char temp[3] = {0};
sendCommand("AT+TEST=TXLRPKT,\"");
for(int i = 0; i < length; i ++)
{
sprintf(temp,"%02x", buffer[i]);
SerialLoRa.write(temp);
}
sendCommand("\"\r\n");
}
short LoRaWanClass::receivePacketP2PMode(unsigned char *buffer, short length, short *rssi, unsigned char timeout)
{
char *ptr;
short number;
while(SerialLoRa.available())SerialLoRa.read();
memset(_buffer, 0, BEFFER_LENGTH_MAX);
readBuffer(_buffer, BEFFER_LENGTH_MAX, timeout);
ptr = strstr(_buffer, "LEN");
if(ptr)number = atoi(ptr + 4);
else number = 0;
if(number <= 0)return 0;
ptr = strstr(_buffer, "RSSI:");
if(ptr)*rssi = atoi(ptr + 5);
else *rssi = -255;
ptr = strstr(_buffer, "RX \"");
if(ptr)
{
ptr += 4;
for(short i = 0; i < number; i ++)
{
char temp[3] = {0};
unsigned char tmp='?', result = 0;
temp[0] = *(ptr + i * 2);
temp[1] = *(ptr + i * 2 + 1);
for(unsigned char j = 0; j < 2; j ++)
{
if((temp[j] >= '0') && (temp[j] <= '9'))
tmp = temp[j] - '0';
else if((temp[j] >= 'A') && (temp[j] <= 'F'))
tmp = temp[j] - 'A' + 10;
else if((temp[j] >= 'a') && (temp[j] <= 'f'))
tmp = temp[j] - 'a' + 10;
result = result * 16 + tmp;
}
if(i < length)buffer[i] = result;
}
}
memset(_buffer, 0, BEFFER_LENGTH_MAX);
return number;
}
// short LoRaWanClass::getBatteryVoltage(void)
// {
// int battery;
// pinMode(CHARGE_STATUS_PIN, OUTPUT);
// digitalWrite(CHARGE_STATUS_PIN, LOW);
// delay(DEFAULT_TIMEWAIT);
// battery = (analogRead(BATTERY_POWER_PIN) * 3300 * 11) >> 10;
// pinMode(CHARGE_STATUS_PIN, INPUT);
// return battery;
// }
// ??? I think this essentially connects the serial port to the LoRa module.
// @@@ typing a "~" will exit
//
void LoRaWanClass::loraDebug(void)
{
char c;
while (true) {
if(SerialUSB.available()) {
c = SerialUSB.read();
if (c == '~')
return;
SerialLoRa.write(c);
}
if(SerialLoRa.available())SerialUSB.write(SerialLoRa.read());
}
}
#if _DEBUG_SERIAL_
//
// timeout is the total amount of time allowed for collecting data
// Would it make more sense if it was the time w/o a character?
void LoRaWanClass::loraDebugPrint(unsigned int timeout)
{
unsigned long timerStart, timerEnd;
char c;
timerStart = millis();
while(1)
{
while(SerialLoRa.available()) {
SerialUSB.write(c = SerialLoRa.read());
if (c == '\n')
return; // !!! This won't work for commands that return multiple lines.
timerStart = millis();
}
timerEnd = millis();
// if(timerEnd - timerStart > 1000 * timeout)break;
if(timerEnd - timerStart > timeout)
break;
}
}
#endif
void LoRaWanClass::debugPrint(const char *str) {
SerialUSB.print(str);
}
void LoRaWanClass::sendCommand(const char *command)
{
SerialLoRa.print(command);
}
void LoRaWanClass::sendCommand(const __FlashStringHelper* command) {
SerialLoRa.print(command);
}
short LoRaWanClass::readBuffer(char *buffer, short length, unsigned char timeout)
{
short i = 0;
unsigned long timerStart, timerEnd;
timerStart = millis();
while(1)
{
if(i < length)
{
while(SerialLoRa.available())
{
char c = SerialLoRa.read();
buffer[i ++] = c;
}
}
timerEnd = millis();
if(timerEnd - timerStart > 1000 * timeout)break;
}
return i;
}
short LoRaWanClass::readLine(char *buffer, short length, unsigned char timeout)
{
short i = 0;
unsigned long timerStart, timerEnd;
char c='\n';
timerStart = millis();
while(1) {
if(i < length-1) {
while(SerialLoRa.available()) {
c = SerialLoRa.read();
buffer[i ++] = c;
if (c == '\n')
break;
timerStart = millis();
}
}
if (c == '\n')
break; // @@@ barf
timerEnd = millis();
if(timerEnd - timerStart > 1000 * timeout)break;
}
buffer[i] = 0; // terminate the string
return i;
}
short LoRaWanClass::waitForResponse(char* response, unsigned char timeout)
{
short len = strlen(response);
short sum = 0;
unsigned long timerStart,timerEnd;
timerStart = millis();
while(1)
{
if(SerialLoRa.available())
{
char c = SerialLoRa.read();
sum = (c == response[sum]) ? sum + 1 : 0;
if(sum == len)break;
}
timerEnd = millis();
if(timerEnd - timerStart > 1000 * timeout)return -1;
}
return 0;
}
short LoRaWanClass::sendCommandAndWaitForResponse(char* command, char *response, unsigned char timeout)
{
sendCommand(command);
return waitForResponse(response, timeout);
}
LoRaWanClass lora;