Inspired by the Arduino Library
After successful proof of concept projects I have build a nanoFramwork library “inspired” by the RakWireless Arduino library.
The initial version only supports my RAK811 LPWAN Evaluation Board(EVB) and STM32F691DISCOVERY based test rig It handles failures, displays error codes/messages, but doesn’t handle all timeouts.
If the RAK811 module is initialised, then connects to the network successfully, the application sends “48656c6c6f204c6f526157414e” (“hello LoRaWAN”) every 20 seconds.

The code application code is now a lot smaller & simpler
public class Program { #if ST_STM32F769I_DISCOVERY private const string SerialPortId = "COM6"; #endif #if OTAA private const string DevEui = "..."; private const string AppEui = "..."; private const string AppKey = "..."; #endif #if ABP private const string devAddress = "..."; private const string nwksKey = "..."; private const string appsKey = "..."; #endif private const byte MessagePort = 1; private const string Payload = "48656c6c6f204c6f526157414e"; // Hello LoRaWAN public static void Main() { Result result; Debug.WriteLine(" devMobile.IoT.Rak811LoRaWanDeviceClient starting"); Debug.WriteLine(Windows.Devices.SerialCommunication.SerialDevice.GetDeviceSelector()); try { using ( Rak811LoRaWanDevice device = new Rak811LoRaWanDevice()) { result = device.Initialise(SerialPortId, SerialParity.None, 8, SerialStopBitCount.One); if (result != Result.Success) { Debug.WriteLine($"Initialise failed {result}"); return; } result = device.Region("AS923"); if (result != Result.Success) { Debug.WriteLine($"Region failed {result}"); return; } #if OTAA result = device.OtaaInitialise(DevEui, AppEui, AppKey); if (result != Result.Success) { Debug.WriteLine($"OTAA Initialise failed {result}"); return; } #endif #if ABP result = device.AbpInitialise(devAddress, nwksKey, appsKey); if (result != Result.Success) { Debug.WriteLine($"ABP Initialise failed {result}"); return; } #endif result = device.Join(new TimeSpan(0,0,10)); if (result != Result.Success) { Debug.WriteLine($"Join failed {result}"); return; } while (true) { result = device.Send(MessagePort, Payload); if (result != Result.Success) { Debug.WriteLine($"Send failed {result}"); } result = device.Sleep(); if (result != Result.Success) { Debug.WriteLine($"Sleep failed {result}"); return; } Thread.Sleep(20000); result = device.Wakeup(); if (result != Result.Success) { Debug.WriteLine($"Wakeup failed {result}"); return; } } } } catch (Exception ex) { Debug.WriteLine(ex.Message); } } }
I compared the debugging output with confirmations off
The thread '<No Name>' (0x2) has exited with code 0 (0x0). devMobile.IoT.Rak811LoRaWanDeviceClient starting COM5,COM6 01:11:13 lora:work_mode TX: send 32 bytes 32 via COM6 RX 01:11:14:UART1 work mode: RUI_UART_NORAMAL Current work_mode:LoRaWAN, join_mode:OTAA, Class: A Initialization OK 01:11:15 lora:region TX: send 33 bytes 33 via COM6 RX 01:11:16:OK 01:11:16 lora:join_mode TX: send 32 bytes 32 via COM6 RX 01:11:17:OK 01:11:18 lora:dev_eui TX: send 45 bytes 45 via COM6 RX 01:11:19:OK 01:11:19 lora:app_eui TX: send 45 bytes 45 via COM6 RX 01:11:20:OK 01:11:21 lora:app_key TX: send 61 bytes 61 via COM6 RX 01:11:22:OK 01:11:22 join TX: send 9 bytes 9 via COM6 RX 01:11:29:OK Join Success TX: send 43 bytes to output stream. TX: 43 bytes via COM6 TX: send 43 bytes to output stream. TX: 43 bytes via COM6 RX :OK TX: send 43 bytes to output stream. TX: 43 bytes via COM6 RX :OK at+recv=1,-54,9,5:48656c6c6f TX: send 43 bytes to output stream. TX: 43 bytes via COM6 TX: send 43 bytes to output stream. TX: 43 bytes via COM6 RX :OK at+recv=2,-51,7,5:48656c6c6f TX: send 43 bytes to output stream. TX: 43 bytes via COM6
Then with confirmations on (note the at+recv=0,-59,7,0) and received messages (at+recv=23,-53,8,5:48656c6c6f)
devMobile.IoT.Rak811LoRaWanDeviceClient starting COM5,COM6 01:20:54 lora:work_mode TX: send 32 bytes 32 via COM6 RX 01:20:56:UART1 work mode: RUI_UART_NORAMAL Current work_mode:LoRaWAN, join_mode:OTAA, Class: A Initialization OK 01:20:56 lora:region TX: send 33 bytes 33 via COM6 RX 01:20:57:OK 01:20:58 lora:join_mode TX: send 32 bytes 32 via COM6 RX 01:20:59:OK 01:20:59 lora:dev_eui TX: send 45 bytes 45 via COM6 RX 01:21:00:OK 01:21:01 lora:app_eui TX: send 45 bytes 45 via COM6 RX 01:21:02:OK 01:21:02 lora:app_key TX: send 61 bytes 61 via COM6 RX 01:21:03:OK 01:21:04 join TX: send 9 bytes 9 via COM6 RX 01:21:11:OK Join Success 01:21:11 lora:confirm TX: send 30 bytes 30 via COM6 RX 01:21:12:OK TX: send 43 bytes to output stream. TX: 43 bytes via COM6 TX: send 43 bytes to output stream. TX: 43 bytes via COM6 TX: send 43 bytes to output stream. TX: 43 bytes via COM6 RX :OK at+recv=23,-53,8,5:48656c6c6f TX: send 43 bytes to output stream. TX: 43 bytes via COM6 TX: send 43 bytes to output stream. TX: 43 bytes via COM6 RX :OK at+recv=0,-59,7,0
In the Visual Studio 2019 debug output I could see the responses to the AT Commands and especially the lack of handling of downlink messages and confirmations from the network.
The next step is to implement timeouts for when operations fail or the module doesn’t respond. Then extend the code to support the receiving of messages as a class A device (missing for the RAK arduino library). I wonder how this will work for when the module is configured as a class C device which can receive messages at any time.
Some commands are quite quick to respond e.g. setting the Region, Sleep, and Wakeup so are most probably ok running synchronously. Other commands can take quite a while e.g. Join, Send, WorkMode so maybe these need to be asynchronous (along with the receiving of confirmations and messages ).
The code is not suitable for production but it confirmed my new approach worked.