RAK3172 Communication

Hello everyone,

I want to communicate between two RAK3172 modules without joining the LoraWAN network. The code in the P2P example joins the LoraWAN network. But i want to communicate between two RAK modules without joining the LoraWAN network. (If possible by entering specific target receiver ID.) I want to prepare the code on Arduino IDE. Can you help me?

Hi @whydont ,

When you select RAK3172 on the Arduino IDE, we have a LoRa P2P example on it.

Another approach can be found here on RUI3 documentation for LoRa P2P.

Thanks for fast reply @carlrowan
I need a code FOR RECEIVER DEVICE, which kind of “api.lorawan.precv” (i don’t even know does it exists or not.). Is there any code to send message to another peer, DIRECTLY?

I found these code but it doesn’t work.

uint8_t buffer[256];
  int size = api.lorawan.preceive(buffer, sizeof(buffer), 0);
  if (size > 0) {
    Serial.print("Received message: ");
    for (int i = 0; i < size; i++) {

While I agree that putting the LoRa P2P part under lorawan in the API is misguided and misleading (if anything, it should be the contrary, as LoRaWAN is derived from LoRa, rather than the contrary), and at best it should be two different modules, the LoRa_P2P example cited by @carlrowan is the code you have to look at. It does NOT join any LoRaWAN network. I know, because I wrote it…

The example is both a receiver and a sender. It sends a packet after receiving one. You have everything there to start coding 2-way communication.

OTOH, keep in mind that the name LoRa P2P is a misnomer. It should be called just LoRa (or LoRa PHY), because it is NOT peer-to-peer. There is nothing in the transport layer to implement addressing or privacy. You have to implement that yourself. Whatever data you send with LoRa will be received by any device in range with the same settings.

@carlrowan This could be a good idea to have 2 standard LoRa_Sender and LoRa_Receiver examples for a future release. :slight_smile:

1 Like

Thank you for sharing the explanatory information.

It is not possible to address within range or send data to a special device, do I understand correctly?

Not quite. I do it all the time. But you need to understand how LoRa works to be able to achieve this:

  1. Remember that LoRa is like talking in a big room full of people. Everybody with good ears with hear you. People at the other end of the room, even if they have good ears, won’t. → range
  2. If you speak English, and the people around you also speak English, they’ll hear AND understand you. If they don’t they will ignore your voice. → LoRa settings
  3. Even if they hear and understand, but realize you’re not talking to them, they’ll be polite (hopefully) and tune you out. → addressing.
  4. Even if they speak English, and are impolite enough to listen, but you speak in a dialect, or in code, they might hear you, maybe understand the words, but will have no clue what you are saying. → Encryption

So you replicate this in LoRa. You select LoRa settings that might put you in a room less crowded (avoid frequencies that are very busy, choose SF/BW carefully, etc). You include an ID at the beginning of the packet. And you encrypt the rest of the packet.

Receivers in your fleet, if in range, will all receive the packet. They will discard it – not for me – except for the device it’s intended for, which will decrypt it and read it. Devices not in your fleet may see the message but will not know what to do…

It’s quite a bit of work, but very doable.

1 Like

Thank you so much, really.

I don’t want to tire you out, but can you suggest a source for these 4 items you mentioned?

4. For the item (Encryption), I looked at an example named RAK3172_AES on the Kongduino GitHub page.

Obviously I need encryption and addressing items a lot.

BTW P2P Example works now:


The RAK3172_AES example on my Github is the right place to start. To do what you want, you should do something like this:

• Put the ID of the sender at the beginning. In a simple scheme, one or two bytes should suffice. Say two bytes for now. so buffer[0] and buffer[1] contain this ID.
• Next put the recipient’s ID. buffer[2] and buffer[3] contain this ID.
• Init an AES context and set up the key:

  struct AES_ctx ctx;
  AES_init_ctx(&ctx, pKey);

• If you’re using ECB, which I don’t recommend, skip the next step. But do try and use CBC.
• Create an Iv of 16 bytes from a random source. Unfortunately there is no good source on rak3172 – at least until the RUI3 team implements my TRNG recommendation, so for now make it just a new one every time, not sequential, and don’t reuse it. Use something like:

for (uint8_t ix = 0; ix < 16; ix++) Iv[ix] = random(0, 256);

• Encrypt your plaintext with encryptCBC((uint8_t*)plainBuf, len, Iv);.
• Copy the Iv to the buffer: memcpy(buffer+4, Iv, 16);
• Copy the ciphertext to the buffer: memcpy(buffer+20, encBuf, len);
• Send the packet (keep in mind the length is len+20).

When receiving it’s basically the reverse:

• Check payload[2] and payload[3] against your ID. If it isn’t, drop and return.
• If it is, init an AES context and set up the key:

  struct AES_ctx ctx;
  AES_init_ctx(&ctx, pKey);

• Decrypt with decryptCBC(buffer+20, len-20, buffer+4);
===> The Iv is buffer[4-19]. The ciphertext in buffer[20+]. The result in decBuf if you follow the code I posted.

That should get you started.

Here is a rewrite of the example, as a set of two: Rx and Tx. This should make things easier.


Thanks for your time and interest.

1 Like