nanoFramework Seeed LoRa-E5 LoRaWAN library Part2

Nasty OTAA connect

After getting basic connectivity for my Seeedstudio LoRa-E5 Development Kit and STM32F691DISCOVERY test rig working I wanted to see if I could get the device connected to The Things Industries(TTI).

My Over the Air Activation (OTAA) implementation is very “nasty” as it is assumed that there are no timeouts or failures and it only sends one BCD message “01020304”.

   public class Program
   {
      private const string SerialPortId = "COM6";

      private const string AppKey = "................................";
      private const string AppEui = "................";

      private const byte MessagePort = 15;

      //private const string Payload = "48656c6c6f204c6f526157414e"; // Hello LoRaWAN
      private const string Payload = "01020304"; // AQIDBA==
      //private const string Payload = "04030201"; // BAMCAQ==

   public static void Main()
   {
      SerialDevice serialDevice;
      uint bytesWritten;
      uint txByteCount;
      uint bytesRead;

      Debug.WriteLine("devMobile.IoT.SeeedLoRaE5.NetworkJoinOTAA starting");

      Debug.WriteLine($"Ports available: {Windows.Devices.SerialCommunication.SerialDevice.GetDeviceSelector()}");

      try
      {
         serialDevice = SerialDevice.FromId(SerialPortId);

         // set parameters
         serialDevice.BaudRate = 9600;
         serialDevice.Parity = SerialParity.None;
         serialDevice.StopBits = SerialStopBitCount.One;
         serialDevice.Handshake = SerialHandshake.None;
         serialDevice.DataBits = 8;

         serialDevice.ReadTimeout = new TimeSpan(0, 0, 5);
         serialDevice.WriteTimeout = new TimeSpan(0, 0, 4);

         DataWriter outputDataWriter = new DataWriter(serialDevice.OutputStream);
         DataReader inputDataReader = new DataReader(serialDevice.InputStream);

         // set a watch char to be notified when it's available in the input stream
         serialDevice.WatchChar = '\n';

         // clear out the RX buffer
         bytesRead = inputDataReader.Load(128);
         while (bytesRead > 0)
         {
            string response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");

            bytesRead = inputDataReader.Load(128);
         }

         // Set the Region to AS923
         bytesWritten = outputDataWriter.WriteString("AT+DR=AS923\r\n");
         Debug.WriteLine($"TX: region {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response
         bytesRead = inputDataReader.Load(128);
         if (bytesRead > 0)
         {
            String response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");
         }

         // Set the Join mode
         bytesWritten = outputDataWriter.WriteString("AT+MODE=LWOTAA\r\n");
         Debug.WriteLine($"TX: mode {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response
         bytesRead = inputDataReader.Load(128);
         if (bytesRead > 0)
         {
            string response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");
         }

         // Set the appEUI
         bytesWritten = outputDataWriter.WriteString($"AT+ID=AppEui,\"{AppEui}\"\r\n");
         Debug.WriteLine($"TX: AppEui {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response
         bytesRead = inputDataReader.Load(128);
         if (bytesRead > 0)
         {
            String response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");
         }

         // Set the appKey
         bytesWritten = outputDataWriter.WriteString($"AT+KEY=APPKEY,{AppKey}\r\n");
         Debug.WriteLine($"TX: AppKey {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response
         bytesRead = inputDataReader.Load(128);
         if (bytesRead > 0)
         {
            String response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");
         }

         // Set the port number
         bytesWritten = outputDataWriter.WriteString($"AT+PORT={MessagePort}\r\n");
         Debug.WriteLine($"TX: port {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response
         bytesRead = inputDataReader.Load(128);
         if (bytesRead > 0)
         {
            String response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");
         }

         // Join the network
         bytesWritten = outputDataWriter.WriteString("AT+JOIN\r\n");
         Debug.WriteLine($"TX: join {outputDataWriter.UnstoredBufferLength} bytes to output stream.");
         txByteCount = outputDataWriter.Store();
         Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

         // Read the response, need loop as multi line response
         bytesRead = inputDataReader.Load(128);
         while (bytesRead > 0)
         {
            String response = inputDataReader.ReadString(bytesRead);
            Debug.WriteLine($"RX :{response}");

            bytesRead = inputDataReader.Load(128);
         }

         while (true)
         {
            bytesWritten = outputDataWriter.WriteString($"AT+MSGHEX=\"{Payload}\"\r\n");
            Debug.WriteLine($"TX: send {outputDataWriter.UnstoredBufferLength} bytes to output stream.");

            txByteCount = outputDataWriter.Store();
            Debug.WriteLine($"TX: {txByteCount} bytes via {serialDevice.PortName}");

            // Read the response, need loop as multi line response
            bytesRead = inputDataReader.Load(128);
            while (bytesRead > 0)
            {
               String response = inputDataReader.ReadString(bytesRead);
               Debug.WriteLine($"RX :{response}");

               bytesRead = inputDataReader.Load(128);
            }

            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.

The thread '<No Name>' (0x2) has exited with code 0 (0x0).
devMobile.IoT.SeeedE5.NetworkJoinOTAA starting
TX: DR 13 bytes
RX :+DR: AS923

TX: MODE 16 bytes
RX :+MODE: LWOTAA

TX: ID=AppEui 40 bytes
RX :+ID: AppEui, ..:..:.:.:.:.:.:.

TX: KEY=APPKEY 48 bytes
RX :+KEY: APPKEY ................................

TX: PORT 11 bytes
RX :+PORT: 1

TX: JOIN 9 bytes
RX :+JOIN: Start
+JOIN: NORMAL
+JOIN: Network joined
+JOIN: NetID 000013 DevAddr ..:..:..:..
+JOIN: Done

TX: MSGHEX 22 bytes
RX :+MSGHEX: Start
+MSGHEX: FPENDING
+MSGHEX: RXWIN1, RSSI -41, SNR 9.0
+MSGHEX: Done

TX: MSGHEX 22 bytes
RX :+MSGHEX: Start
+MSGHEX: Done

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

Seeed E5 LoRaWAN dev Kit connecting in The Things Industries Device Live data tab

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.