Skip to content

Class C support #260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ script:
- test/verify arduino:avr:leonardo examples/PassThrough/PassThrough.ino
- test/verify arduino:avr:leonardo examples/QuickStart/QuickStart.ino
- test/verify arduino:avr:leonardo examples/Receive/Receive.ino
- test/verify arduino:avr:leonardo examples/ReceiveClassC/ReceiveClassC.ino
- test/verify arduino:avr:leonardo examples/SendOTAA/SendOTAA.ino
- test/verify arduino:avr:leonardo examples/Sensors/DHT/DHT.ino
- test/verify arduino:avr:leonardo examples/Sensors/LightSensor/LightSensor.ino
Expand Down
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Johan Stokking <johan@thethingsnetwork.org>
Fokke Zandbergen <mail@fokkezb.nl>
Alessandro Blason <mrblason@gmail.com>
JP Meijers <git@jpmeijers.com>
19 changes: 18 additions & 1 deletion docs/TheThingsNetwork.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,15 @@ See the [Receive](https://github.com/TheThingsNetwork/arduino-device-lib/blob/ma
Activate the device via OTAA (default).

```c
bool join(const char *appEui, const char *appKey, int8_t retries = -1, uint32_t retryDelay = 10000);
bool join(const char *appEui, const char *appKey, int8_t retries = -1, uint32_t retryDelay = 10000, lorawan_class = CLASS_A);
bool join(int8_t retries = -1, uint32_t retryDelay = 10000);
```

- `const char *appEui`: Application EUI the device is registered to.
- `const char *appKey`: Application Key assigned to the device.
- `int8_t retries = -1`: Number of times to retry after failed or unconfirmed join. Defaults to `-1` which means infinite.
- `uint32_t retryDelay = 10000`: Delay in ms between attempts. Defaults to 10 seconds.
- `lorawan_class = CLASS_A`: The LoRaWAN class to use for downlink message reception.

Returns `true` or `false` depending on whether it received confirmation that the activation was successful before the maximum number of attempts.

Expand All @@ -127,6 +128,22 @@ Call the method with no arguments if the device's LoRa module comes with pre-fla

See the [SendABP](https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/SendABP/SendABP.ino) example.

## Method: `setClass`

Change the downlink receive LoRaWAN Class. Class C is only supported in firmware version 1.0.5 and up. For other firmware versions this method will have no effect.

```c
bool setClass(lorawan_class p_lw_class);
```

- `lorawan_class p_lw_class`: The LoRaWAN class. Either `CLASS_A` or `CLASS_C`.

Returns `true` if the change was successful, or `false` if not successful.

The receive window only opens after a transmit. Therefore Class C receive will only start after calling `sendBytes()`.

See the [ReceiveClassC](https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/ReceiveClassC/ReceiveClassC.ino) example.

## Method: `sendBytes`

Send a message to the application using raw bytes.
Expand Down
60 changes: 60 additions & 0 deletions examples/ReceiveClassC/ReceiveClassC.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <TheThingsNetwork.h>

// Set your AppEUI and AppKey
const char *appEui = "0000000000000000";
const char *appKey = "00000000000000000000000000000000";

#define loraSerial Serial1
#define debugSerial Serial

// Replace REPLACE_ME with TTN_FP_EU868 or TTN_FP_US915
#define freqPlan REPLACE_ME

TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan);

void setup()
{
loraSerial.begin(57600);
debugSerial.begin(9600);

// Wait a maximum of 10s for Serial Monitor
while (!debugSerial && millis() < 10000)
;

// Set callback for incoming messages
ttn.onMessage(message);

debugSerial.println("-- STATUS");
ttn.showStatus();

debugSerial.println("-- JOIN");
ttn.join(appEui, appKey, -1, 10000, CLASS_C);

// Class C RX only takes affect after a TX
uint8_t payload[] = {0x00};
ttn.sendBytes(payload, 1);
}

void loop()
{
debugSerial.println("-- LOOP");

// Check for received data.
ttn.poll();

// When using Class C we can poll as quickly as we can, as we only check the serial buffer.
//delay(1000);
}

void message(const uint8_t *payload, size_t size, port_t port)
{
debugSerial.println("-- MESSAGE");
debugSerial.print("Received " + String(size) + " bytes on port " + String(port) + ":");

for (int i = 0; i < size; i++)
{
debugSerial.print(" " + String(payload[i]));
}

debugSerial.println();
}
6 changes: 6 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ TheThingsNode KEYWORD1
ttn_port_t KEYWORD1
ttn_response_t KEYWORD1
ttn_fp_t KEYWORD1
lorawan_class_t KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
Expand All @@ -23,6 +24,7 @@ onMessage KEYWORD2
provision KEYWORD2
join KEYWORD2
personalize KEYWORD2
setClass KEYWORD2
sendBytes KEYWORD2
poll KEYWORD2

Expand Down Expand Up @@ -91,3 +93,7 @@ TTN_CYAN LITERAL1
TTN_MAGENTA LITERAL1
TTN_WHITE LITERAL1
TTN_BLACK LITERAL1

CLASS_A LITERAL1
CLASS_B LITERAL1
CLASS_C LITERAL1
83 changes: 78 additions & 5 deletions src/TheThingsNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,9 @@ const char mac_rx2[] PROGMEM = "rx2";
const char mac_ch[] PROGMEM = "ch";
const char mac_gwnb[] PROGMEM = "gwnb";
const char mac_mrgn[] PROGMEM = "mrgn";
const char mac_class[] PROGMEM = "class";

const char *const mac_options[] PROGMEM = {mac_devaddr, mac_deveui, mac_appeui, mac_nwkskey, mac_appskey, mac_appkey, mac_pwridx, mac_dr, mac_adr, mac_bat, mac_retx, mac_linkchk, mac_rxdelay1, mac_rxdelay2, mac_band, mac_ar, mac_rx2, mac_ch, mac_gwnb, mac_mrgn};
const char *const mac_options[] PROGMEM = {mac_devaddr, mac_deveui, mac_appeui, mac_nwkskey, mac_appskey, mac_appkey, mac_pwridx, mac_dr, mac_adr, mac_bat, mac_retx, mac_linkchk, mac_rxdelay1, mac_rxdelay2, mac_band, mac_ar, mac_rx2, mac_ch, mac_gwnb, mac_mrgn, mac_class};

#define MAC_DEVADDR 0
#define MAC_DEVEUI 1
Expand All @@ -215,6 +216,7 @@ const char *const mac_options[] PROGMEM = {mac_devaddr, mac_deveui, mac_appeui,
#define MAC_CH 17
#define MAC_GWNB 18
#define MAC_MRGN 19
#define MAC_CLASS 20

const char mac_join_mode_otaa[] PROGMEM = "otaa";
const char mac_join_mode_abp[] PROGMEM = "abp";
Expand Down Expand Up @@ -545,9 +547,36 @@ bool TheThingsNetwork::join(int8_t retries, uint32_t retryDelay)
return false;
}

bool TheThingsNetwork::join(const char *appEui, const char *appKey, int8_t retries, uint32_t retryDelay)
bool TheThingsNetwork::setClass(lorawan_class_t p_lw_class)
{
return provision(appEui, appKey) && join(retries, retryDelay);
switch(p_lw_class)
{

case CLASS_A:
{
lw_class = p_lw_class;
return sendMacSet(MAC_CLASS, "a");
}

// case CLASS_B: // Not yet supported. Use default case.

case CLASS_C:
{
bool result = sendMacSet(MAC_CLASS, "c");
// Older firmware does not support Class C. If setting change fails, keep on using Class A.
if(result) lw_class = p_lw_class;
return result;
}

default:
return false;

}
}

bool TheThingsNetwork::join(const char *appEui, const char *appKey, int8_t retries, uint32_t retryDelay, lorawan_class_t p_lw_class)
{
return provision(appEui, appKey) && join(retries, retryDelay) && setClass(p_lw_class);
}

ttn_response_t TheThingsNetwork::sendBytes(const uint8_t *payload, size_t length, port_t port, bool confirm, uint8_t sf)
Expand Down Expand Up @@ -603,8 +632,52 @@ ttn_response_t TheThingsNetwork::sendBytes(const uint8_t *payload, size_t length

ttn_response_t TheThingsNetwork::poll(port_t port, bool confirm)
{
uint8_t payload[] = {0x00};
return sendBytes(payload, 1, port, confirm);
switch(lw_class)
{

case CLASS_A:
{
// Class A: send uplink and wait for rx windows
uint8_t payload[] = {0x00};
return sendBytes(payload, 1, port, confirm);
}

// case CLASS_B: // Not yet supported. Use default case.

case CLASS_C:
{
// Class C: check rx buffer for any recevied data
memset(buffer, 0, sizeof(buffer));

long timeout = this->modemStream->getTimeout();
this->modemStream->setTimeout(100);
this->modemStream->readBytesUntil('\n', buffer, sizeof(buffer));
this->modemStream->setTimeout(timeout);

if (pgmstrcmp(buffer, CMP_MAC_RX) == 0)
{
port_t downlinkPort = receivedPort(buffer + 7);
char *data = buffer + 7 + digits(downlinkPort) + 1;
size_t downlinkLength = strlen(data) / 2;
if (downlinkLength > 0)
{
uint8_t downlink[downlinkLength];
for (size_t i = 0, d = 0; i < downlinkLength; i++, d += 2)
{
downlink[i] = TTN_HEX_PAIR_TO_BYTE(data[d], data[d + 1]);
}
if (messageCallback)
{
messageCallback(downlink, downlinkLength, downlinkPort);
}
}
return TTN_SUCCESSFUL_RECEIVE;
}
}

default:
return TTN_UNSUCESSFUL_RECEIVE;
}
}

void TheThingsNetwork::showStatus()
Expand Down
14 changes: 12 additions & 2 deletions src/TheThingsNetwork.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ enum ttn_response_t
TTN_ERROR_SEND_COMMAND_FAILED = (-1),
TTN_ERROR_UNEXPECTED_RESPONSE = (-10),
TTN_SUCCESSFUL_TRANSMISSION = 1,
TTN_SUCCESSFUL_RECEIVE = 2
TTN_SUCCESSFUL_RECEIVE = 2,
TTN_UNSUCESSFUL_RECEIVE = 3
};

enum ttn_fp_t
Expand All @@ -47,6 +48,13 @@ enum ttn_fp_t
TTN_FP_IN865_867
};

enum lorawan_class_t
{
CLASS_A,
CLASS_B,
CLASS_C
};

class TheThingsNetwork
{
private:
Expand All @@ -59,6 +67,7 @@ class TheThingsNetwork
char buffer[512];
bool baudDetermined = false;
void (*messageCallback)(const uint8_t *payload, size_t size, port_t port);
lorawan_class_t lw_class = CLASS_A;

void clearReadBuffer();
size_t readLine(char *buffer, size_t size, uint8_t attempts = 3);
Expand Down Expand Up @@ -99,10 +108,11 @@ class TheThingsNetwork
uint16_t getVDD();
void onMessage(void (*cb)(const uint8_t *payload, size_t size, port_t port));
bool provision(const char *appEui, const char *appKey);
bool join(const char *appEui, const char *appKey, int8_t retries = -1, uint32_t retryDelay = 10000);
bool join(const char *appEui, const char *appKey, int8_t retries = -1, uint32_t retryDelay = 10000, lorawan_class_t = CLASS_A);
bool join(int8_t retries = -1, uint32_t retryDelay = 10000);
bool personalize(const char *devAddr, const char *nwkSKey, const char *appSKey);
bool personalize();
bool setClass(lorawan_class_t p_lw_class);
ttn_response_t sendBytes(const uint8_t *payload, size_t length, port_t port = 1, bool confirm = false, uint8_t sf = 0);
ttn_response_t poll(port_t port = 1, bool confirm = false);
void sleep(uint32_t mseconds);
Expand Down