Nasty ABP connect
After getting basic connectivity for my RAK3172 test rig sorted I wanted to see if I could get the device connected to The Things Network(TTN) via the RAK7246G LPWAN Developer Gateway on my bookcase.
My Activation By Personalisation (ABP) implementation is very “nasty” (just like the OTAA one) I have assumed that there would be no timeouts or failures and I only send one BCD message “48656c6c6f204c6f526157414e” which is “hello LoRaWAN”.
The code just sequentially steps through the necessary configuration to join the TTN network with a suitable delay after each command is sent.
//---------------------------------------------------------------------------------
// Copyright (c) September 2021, devMobile Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//---------------------------------------------------------------------------------
namespace devMobile.IoT.NetCore.RAK3172.NetworkJoinABP
{
using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Threading;
public class Program
{
private const string SerialPortId = "/dev/ttyS0";
private const string DevAddress = "...";
private const string NwksKey = "...";
private const string AppsKey = "...";
private const byte MessagePort = 1;
private const string Payload = "A0EEE456D02AFF4AB8BAFD58101D2A2A"; // Hello LoRaWAN
public static void Main()
{
string response;
Debug.WriteLine("devMobile.IoT.NetCore.Rak3172.NetworkJoinOTAA starting");
Debug.WriteLine(String.Join(",", SerialPort.GetPortNames()));
try
{
using (SerialPort serialPort = new SerialPort(SerialPortId))
{
// set parameters
serialPort.BaudRate = 9600;
serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.Handshake = Handshake.None;
serialPort.ReadTimeout = 5000;
serialPort.NewLine = "\r\n";
serialPort.Open();
// clear out the RX buffer
response = serialPort.ReadExisting();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
Thread.Sleep(500);
// Set the Working mode to LoRaWAN
Console.WriteLine("Set Work mode");
serialPort.WriteLine("AT+NWM=1");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the Region to AS923
Console.WriteLine("Set Region");
serialPort.WriteLine("AT+BAND=8-1");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the JoinMode
Console.WriteLine("Set Join mode");
serialPort.WriteLine("AT+NJM=0");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the device address
Console.WriteLine("Set Device Address");
serialPort.WriteLine($"AT+DEVADDR={DevAddress}");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the network session key
Console.WriteLine("Set Network Session Key");
serialPort.WriteLine($"AT+NWKSKEY={NwksKey}");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the application session key
Console.WriteLine("Set application Session Key");
serialPort.WriteLine($"AT+APPSKEY={AppsKey}");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Set the Confirm flag
Console.WriteLine("Set Confirm off");
serialPort.WriteLine("AT+CFM=0");
// Read the blank line
response = serialPort.ReadLine();
// Read the response
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
// Join the network
Console.WriteLine("Start Join");
serialPort.WriteLine("AT+JOIN=1:0:10:2");
// Read the blank line
response = serialPort.ReadLine();
// Read the Result
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
Thread.Sleep(10000);
// Read the +EVT:JOINED
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
while (true)
{
Console.WriteLine("Sending");
serialPort.WriteLine($"AT+SEND={MessagePort}:{Payload}");
// Read the blank line
response = serialPort.ReadLine();
// Read the result
Console.WriteLine("Send result");
response = serialPort.ReadLine();
Debug.WriteLine($"RX :{response.Trim()} bytes:{response.Length}");
Thread.Sleep(300000);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
The code is not suitable for production but it confirmed my software and hardware configuration worked.

In the Visual Studio 2019 debug output I could see messages getting sent and then after a short delay they were visible in the TTN console.

The RAK3172 command format is quite different from other modules I have used e.g. Requesting the firmware version information
- TX- AT+VER=?
- RX- Blank Line
- RX- V1.0.2
- RX- OK
Requesting the APPEUI
- TX- AT+DEVADDR=?
- RX- 11223344
- RX- Blank line
- RX- OK
I think the RAK3172 module ships with a default DEVEUI so in this code and my library I have assumed it will be configured as part of a “provisioning” process.
Pingback: .NET Core RAK3172 LoRaWAN library Part4 | devMobile's blog
Pingback: .NET Core RAK3172 LoRaWAN library Part5 | devMobile's blog