After getting my RAKwireless RAK4200 module to reliably connect to The Things Network(TTN) using Over The Air Activation(OTAA) the next step was to built an Activation By Personalisation(ABP) sample application.

I modified the NetworkJoinOTAA sample(based on the asynchronous version of BreakOutSerial) to send the required sequence of AT commands and display the responses.
namespace devMobile.IoT.LoRaWAN.nanoFramework.RAK4200
{
using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;
#if ESP32_WROOM
using global::nanoFramework.Hardware.Esp32; ///need NuGet nanoFramework.Hardware.Esp32
#endif
public class Program
{
#if ST_STM32F769I_DISCOVERY
private const string SerialPortId = "COM6";
#endif
#if ESP32_WROOM
private const string SerialPortId = "COM2";
#endif
private const string DevEui = "...";
private const string AppEui = "...";
private const string AppKey = "...";
private const byte MessagePort = 1;
private const string Payload = "01020304"; // Is AQIDBA==
public static void Main()
{
string response;
Debug.WriteLine("devMobile.IoT.Rak4200.NetworkJoinOTAA starting");
try
{
#if ESP32_WROOM
Configuration.SetPinFunction(Gpio.IO16, DeviceFunction.COM2_TX);
Configuration.SetPinFunction(Gpio.IO17, DeviceFunction.COM2_RX);
#endif
Debug.Write("Ports:");
foreach (string port in SerialPort.GetPortNames())
{
Debug.Write($" {port}");
}
Debug.WriteLine("");
using (SerialPort serialDevice = new SerialPort(SerialPortId))
{
// set parameters
serialDevice.BaudRate = 9600;
//_SerialPort.BaudRate = 115200;
serialDevice.Parity = Parity.None;
serialDevice.StopBits = StopBits.One;
serialDevice.Handshake = Handshake.None;
serialDevice.DataBits = 8;
serialDevice.ReadTimeout = 10000;
//serialDevice.ReadBufferSize = 128;
//serialDevice.ReadBufferSize = 256;
serialDevice.ReadBufferSize = 512;
//serialDevice.ReadBufferSize = 1024;
serialDevice.NewLine = "\r\n";
serialDevice.DataReceived += SerialDevice_DataReceived;
serialDevice.Open();
serialDevice.WatchChar = '\n';
// clear out the RX buffer
serialDevice.ReadExisting();
response = serialDevice.ReadExisting();
Debug.WriteLine($"Response :{response.Trim()} bytes:{response.Length}");
Thread.Sleep(500);
// Set the Working mode to LoRaWAN
Debug.WriteLine("lora:work_mode:0");
serialDevice.WriteLine("at+set_config=lora:work_mode:0");
Thread.Sleep(1500);
// Set the JoinMode
Debug.WriteLine("lora:join_mode");
serialDevice.WriteLine("at+set_config=lora:join_mode:0");
Thread.Sleep(500);
// Set the Class
Debug.WriteLine("lora:class");
serialDevice.WriteLine("at+set_config=lora:class:0");
Thread.Sleep(500);
// Set the Region to AS923
Debug.WriteLine("lora:region");
serialDevice.WriteLine("at+set_config=lora:region:AS923");
Thread.Sleep(500);
// Set the devEUI
Debug.WriteLine("lora:dev_eui");
serialDevice.WriteLine($"at+set_config=lora:dev_eui:{DevEui}");
Thread.Sleep(500);
// Set the appEUI
Debug.WriteLine("lora:app_eui");
serialDevice.WriteLine($"at+set_config=lora:app_eui:{AppEui}");
Thread.Sleep(500);
// Set the appKey
Debug.WriteLine("lora:app_key");
serialDevice.WriteLine($"at+set_config=lora:app_key:{AppKey}");
Thread.Sleep(500);
// Set the Confirm flag
Debug.WriteLine("lora:confirm");
serialDevice.WriteLine("at+set_config=lora:confirm:0");
Thread.Sleep(500);
Debug.WriteLine("lora:adr");
serialDevice.WriteLine("at+set_config=lora:adr:1");
Thread.Sleep(500);
// Join the network
Debug.WriteLine("at+join");
serialDevice.WriteLine("at+join");
Thread.Sleep(10000);
byte counter = 1;
while (true)
{
// Send the BCD messages
string payload = $"{Payload}{counter:X2}";
Debug.WriteLine($"at+send=lora:{MessagePort}:{payload}");
serialDevice.WriteLine($"at+send=lora:{MessagePort}:{payload}");
counter += 1;
Thread.Sleep(300000);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private static void SerialDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort = (SerialPort)sender;
string response;
switch (e.EventType)
{
case SerialData.Chars:
break;
case SerialData.WatchChar:
response = serialPort.ReadExisting();
Debug.Write(response);
break;
default:
Debug.Assert(false, $"e.EventType {e.EventType} unknown");
break;
}
}
}
}
The NetworkJoinABP application assumes that all of the AT commands succeed.
I have been using at+set_config=lora:default_parameters set the WisDuo RAK4200 back to factory settings so I can figure out what settings are persisted by a “at+set_config=device:restart” and which ones need to be set every time the application is run.