GPS Example isn't working, nothing in serial log or console

I can’t get the gps example to output anything in the serial log. I have changed out the correct keys to helium network as well and am not getting any response on the network either? The keys are the only thing I altered in the code. Any idea what is going wrong here?
GPS Tracker Code

image

Do you have any error/warning during compilation? Is the region correct? Can you verify if you are within a working Helium hotspot?

Ahh I waited a bit and it is working now!

I noticed the payload decoder doesn’t have a field name like temperature does, how do I attach datacake widget to pick up the location on the map? How can I add a field name so I can plug in the data into the widget to view the location on a map

There is a part in the code that checks the orientation of the device using the accelerometer. You have to re-orient the device so that it will start to transmit GPS data if you have a GPS fix already.

image

On the decoder side, this is the one you should use WisBlock/examples/RAK4630/solutions/GPS_Tracker at master · RAKWireless/WisBlock · GitHub.

How do I attach datacake widget to pick up the location on the map? How can I add a field name so I can plug in the data into the widget to view the location on a map. The other decode has field names like humidity and i type those field names in to pick up the data on the widget but this gps decoder doesn’t have that

image

image
The guy from datacake sent me this, saying there is a problem with the gps. Any idea what is going on?
image

If you do not see the same payload size as Simon, then you probably don’t have GPS data. You should check first if you got the coordinates.

Again were you able to satisfy the if( abs(x-z) < 400) condition I’ve said above?

What is the live data feed in you TTN application?

Can you try to check in serial monitor the logs of GPS module by uncommenting this line 371? If you uncomment this, you will see lots of NMEA codes coming from the GPS model, you should not uncomment this permanently but only for troubleshooting.

Yea, when I stand it usb port facing to the sky it will transmit data, but that is where I am getting the bad data.

15:42:19.530 → check acc!
15:42:19.530 → X = 144.12mg Y = 944.77mg Z =-80.07mg
15:42:19.530 → $GPTXT,01,01,02,ANTSTATUS=INIT25
15:42:20.127 → $GPRMC,V,N
53
15:42:20.127 → $GP$GPRMC,V,N53
15:42:20.193 → $GPVTG,N
30
15:42:20.193 → $GPGGA,0,00,99.99,48
15:42:20.193 → $GPGSA,A,1,99.99,99.99,99.99
30
15:42:20.260 → $GPGSV,1,1,01,07,2974
15:42:20.524 → $GPGLL,V,N
64
15:42:20.524 → No Location Found
15:42:30.529 → check acc!
15:42:30.529 → X = 144.12mg Y = 944.77mg Z =-64.05mg
15:42:30.529 → $GPRMC,V,N53
15:42:31.059 → $GPVTG,N
30
15:42:31.059 → $GPGGA,0,00,$GPRMC,214233.00,V,N78
15:42:31.125 → $GPVTG,N
30
15:42:31.125 → $GPGGA,214233.00,0,00,99.99,63
15:42:31.191 → $GPGSA,A,1,99.99,99.99,99.99
30
15:42:31.191 → $GPGSV,1,1,03,07,29,09,22,13,237C
15:42:31.522 → $GPGLL,214233.00,V,N
4F
15:42:31.522 → No Location Found

15:46:44.157 → =====================================
15:46:44.157 → Welcome to RAK4630 LoRaWan!!!
15:46:44.157 → Type: OTAA
15:46:44.157 → Region: US915
15:46:44.157 → =====================================
15:46:44.157 → Sensor at 0x18 started.
15:46:46.344 → gps uart init ok!
15:46:51.912 → OTAA Mode, Network Joined!
15:47:02.887 → check acc!
15:47:02.887 → X = 80.07mg Y = 960.78mg Z =48.04mg
15:47:02.887 → $GPTXT,01,01,02,ANTSTATUS=INIT25
15:47:03.517 → $GPRMC,V,N
53
15:47:03.517 → $GP$GPRMC,V,N53
15:47:03.583 → $GPVTG,N
30
15:47:03.583 → $GPGGA,0,00,99.99,48
15:47:03.583 → $GPGSA,A,1,99.99,99.99,99.99
30
15:47:03.649 → $GPGSV,1,1,04,01,23,03,22,05,24,06,257C
15:47:03.915 → $GPGLL,V,N
64
15:47:03.915 → No Location Found

That’s good that you see NMEA logs. Can you try to go outside or near window and probably wait for a couple of minutes to see if the GPS can get a fix? It might take awhile if your module hasn’t got a fix yet. Probably at least 2minutes. If you got a GPS data, the NMEA codes will look longer and more alive :smiley:

You should not see also the note No Location Found.

16:03:11.088 → X = 80.07mg Y = 960.78mg Z =32.03mg
16:03:11.088 → $GPRMC,220301.00,A,3506.61321,N,09226.97117,W,0.562,100122,A$GPRMC,220311.00,A,3506.61551,N,09226.96981,W,0.144,100122,A66
16:03:11.187 → $GPVTG,T,M,0.144,N,0.266,K,A
20
16:03:11.388 → $GPGGA,220311.00,3506.61551,N,09226.96981,W,1,05,3.07,122.0,M,-28.6,M,6A
16:03:11.388 → $GPGSA,A,3,14,08,30,27,07,3.75,3.07,2.15
0D
16:03:11.388 → $GPGSV,3,1,12,01,13,146,04,15,172,20,07,73,344,28,08,55,053,237B
16:03:11.453 → $GPGSV,3,2,12,09,39,201,17,13,01,327,14,27,270,26,16,03,067,17
7A
16:03:11.520 → $GPGSV,3,3,12,17,08,209,21,26,117,20,27,23,042,18,30,46,316,2879
16:03:11.586 → $GPGLL,3506.61551,N,09226.96981,W,220311.00,A,A
7E
16:03:12.084 → lmh_send ok count 1
16:03:22.093 → check acc!
16:03:22.093 → X = 80.07mg Y = 960.78mg Z =48.04mg
16:03:22.093 → $GPRMC,220312.00,A,3506.61548,N,09226.96964,W,0.067,100122,A0,A,3506.61440,N,09226.97003,W,0.386,100122,A69
16:03:22.192 → $GPVTG,T,M,0.386,N,0.715,K,A
2D
16:03:22.192 → $GPGGA,220322.00,3506.61440,N,09226.97003,W,1,05,3.08,120.7,M,-28.6,M,63
16:03:22.325 → $GPGSA,A,3,14,08,30,27,07,3.75,3.08,2.15
02
16:03:22.325 → $GPGSV,3,1,12,01,13,146,04,15,172,22,07,73,344,28,08,55,053,2278
16:03:22.391 → $GPGSV,3,2,12,09,39,201,11,13,01,327,14,27,270,25,16,03,067,17
7F
16:03:22.523 → $GPGSV,3,3,12,17,08,209,21,21,27,117,22,27,22,042,17,30,46,316,2778
16:03:23.087 → $GPGLL,3506.61440,N,09226.97003,W,220322.00,A,A
7D
16:03:23.087 → $GPRMC,220323.lmh_send ok count 2

Started doing this, but it was sending data before and he said it wasn’t right I didn’t have this nmea log though

can’t you see your coordinates here?

can you try to print the longitude and lattitude data?

Add Serial.println(ilat) and Serial.println(ilon) just like in the code below.

    if (newData)
    {
      unsigned long age;  
      gps.f_get_position(&flat, &flon, &age);
      flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat;
      ilat = flat * 100000;
      Serial.println(ilat);
      flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon;
      ilon = flon * 100000;
      Serial.println(ilon);
      memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
      m_lora_app_data.port = gAppPort;
      m_lora_app_data.buffer[0] = 0x09;
      //lat data

I took it outside for a bit and it still didn’t transmit any packets, my laptop is dead so I couldn’t get a log. I ordered an lcd screen from u guys hoping maybe I can use that to see. How long do I leave it out there? Also is there any way to not have to turn the chip straight up the entire time to get the gps to work?

You need to charge your laptop and see if you are really getting the coordinates properly :wink:

You can use the OLED and it will require you do to some programming and modification. If you can’t really get out with your laptop, you can try to transmit the coordinates via BLE as well so you can view it in your smartphone. You have to code this part as well.

If you are outside and in good sight of the sky, I’ll leave for 5 minutes. If nothing is happening, I will check if the antenna is properly connected and in the right orientation (sticker facing the sky).

Btw, I think you already have GPS coordinates in your last post.

I walked outside for well over 5 minutes and no packets were sent. Just to go back over this, I have this setup below on the hardware side and I have the 3 axis on the slot below. I don’t have a laptop but I have that lipo battery so I walked around outside and watched the helium console and I always get a join accept/request but no packets sent which tells me there is no location found I believe. idk What else to do, any ideas? Btw it’s not a matter of charging it, I threw a left hook in my sleep and broke it pretty much lol, so I ordered another one but it won’t be here til Feb.

Also your github code and the docs on the rak website are different I believe, which one should I use and is the most up to date?

Hi @a1projects ,

To send packets, you need to orient your wisblock module properly just like what you did before. Also, it is really hard to troubleshoot if we don’t have logs. I already see GPS coordinates in your log last time. We should see that again and see the packets going to TTN.

Can you help me point the difference you said? I’ll check and update if necessary. Thank you.

First Code

/**
 * @file GPS_Tracker.ino
 * @author rakwireless.com
 * @brief This sketch demonstrate a GPS tracker that collect location from a uBlox M7 GNSS sensor
 *    and send the data to lora gateway.
 *    It uses a 3-axis acceleration sensor to detect movement of the tracker
 * @version 0.2
 * @date 2021-04-30
 * 
 * @copyright Copyright (c) 2020
 * 
 * @note RAK4631 GPIO mapping to nRF52840 GPIO ports
   RAK4631    <->  nRF52840
   WB_IO1     <->  P0.17 (GPIO 17)
   WB_IO2     <->  P1.02 (GPIO 34)
   WB_IO3     <->  P0.21 (GPIO 21)
   WB_IO4     <->  P0.04 (GPIO 4)
   WB_IO5     <->  P0.09 (GPIO 9)
   WB_IO6     <->  P0.10 (GPIO 10)
   WB_SW1     <->  P0.01 (GPIO 1)
   WB_A0      <->  P0.04/AIN2 (AnalogIn A2)
   WB_A1      <->  P0.31/AIN7 (AnalogIn A7)
 */

#include <Arduino.h>
#include <LoRaWan-RAK4630.h> //http://librarymanager/All#SX126x
#include <SPI.h>
#include "SparkFunLIS3DH.h" //http://librarymanager/All#SparkFun-LIS3DH
#include "Wire.h"
#include <TinyGPS.h>        //http://librarymanager/All#TinyGPS

LIS3DH SensorTwo(I2C_MODE, 0x18);

TinyGPS gps;

String tmp_data = "";
int direction_S_N = 0;  //0--S, 1--N
int direction_E_W = 0;  //0--E, 1--W

// RAK4630 supply two LED
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = true;   // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60                     /**< Maximum number of events in the scheduler queue. */
#define LORAWAN_DATERATE DR_0                   /*LoRaMac datarates definition, from DR_0 to DR_5*/
#define LORAWAN_TX_POWER TX_POWER_5             /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/
#define JOINREQ_NBTRIALS 3                      /**< Number of trials for the join request. */
DeviceClass_t gCurrentClass = CLASS_A;          /* class definition*/
LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_US915;    /* Region:EU868*/
lmh_confirm gCurrentConfirm = LMH_UNCONFIRMED_MSG;          /* confirm/unconfirm packet definition*/
uint8_t gAppPort = LORAWAN_APP_PORT;                      /* data port*/

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
 */
static lmh_param_t lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF};

// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                        lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler
                                       };
                                       
//OTAA keys !!!! KEYS ARE MSB !!!!

// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64                     /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 10000                        /**< Defines for user timer, the application data transmission interval. 10s, value in [ms]. */
static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];        //< Lora user application data buffer.
static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t appTimer;
static uint32_t timers_init(void);
static uint32_t count = 0;
static uint32_t count_fail = 0;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Initialize Serial for debug output
  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }

  // Initialize LoRa chip.
  lora_rak4630_init();

  Serial.println("=====================================");
  Serial.println("Welcome to RAK4630 LoRaWan!!!");
  if (doOTAA)
  {
    Serial.println("Type: OTAA");
  }
  else
  {
    Serial.println("Type: ABP");
  }

  switch (gCurrentRegion)
  {
    case LORAMAC_REGION_AS923:
      Serial.println("Region: AS923");
      break;
    case LORAMAC_REGION_AU915:
      Serial.println("Region: AU915");
      break;
    case LORAMAC_REGION_CN470:
      Serial.println("Region: CN470");
      break;
  case LORAMAC_REGION_CN779:
    Serial.println("Region: CN779");
    break;
    case LORAMAC_REGION_EU433:
      Serial.println("Region: EU433");
      break;
    case LORAMAC_REGION_IN865:
      Serial.println("Region: IN865");
      break;
    case LORAMAC_REGION_EU868:
      Serial.println("Region: EU868");
      break;
    case LORAMAC_REGION_KR920:
      Serial.println("Region: KR920");
      break;
    case LORAMAC_REGION_US915:
      Serial.println("Region: US915");
    break;
  case LORAMAC_REGION_RU864:
    Serial.println("Region: RU864");
    break;
  case LORAMAC_REGION_AS923_2:
    Serial.println("Region: AS923-2");
    break;
  case LORAMAC_REGION_AS923_3:
    Serial.println("Region: AS923-3");
    break;
  case LORAMAC_REGION_AS923_4:
    Serial.println("Region: AS923-4");
      break;
  }
  Serial.println("=====================================");

  //lis3dh init
  if (SensorTwo.begin() != 0)
  {
    Serial.println("Problem starting the sensor at 0x18.");
  }
  else
  {
    Serial.println("Sensor at 0x18 started.");
  // Set low power mode
  uint8_t data_to_write = 0;
  SensorTwo.readRegister(&data_to_write, LIS3DH_CTRL_REG1);
  data_to_write |= 0x08;
  SensorTwo.writeRegister(LIS3DH_CTRL_REG1, data_to_write);
  delay(100);

  data_to_write = 0;
  SensorTwo.readRegister(&data_to_write, 0x1E);
  data_to_write |= 0x90;
  SensorTwo.writeRegister(0x1E, data_to_write);
  delay(100);
  }
  //gps init

  pinMode(WB_IO2, OUTPUT);
  digitalWrite(WB_IO2, 0);
  delay(1000);
  digitalWrite(WB_IO2, 1);
  delay(1000);
  
  Serial1.begin(9600);
  while (!Serial1);
  Serial.println("gps uart init ok!");
  
  //creat a user timer to send data to server period
  uint32_t err_code;

  err_code = timers_init();
  if (err_code != 0)
  {
    Serial.printf("timers_init failed - %d\n", err_code);
    return;
  }

  // Setup the EUIs and Keys
  if (doOTAA)
  {
    lmh_setDevEui(nodeDeviceEUI);
    lmh_setAppEui(nodeAppEUI);
    lmh_setAppKey(nodeAppKey);
  }
  else
  {
    lmh_setNwkSKey(nodeNwsKey);
    lmh_setAppSKey(nodeAppsKey);
    lmh_setDevAddr(nodeDevAddr);
  }

  // Initialize LoRaWan
  err_code = lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion);
  if (err_code != 0)
  {
    Serial.printf("lmh_init failed - %d\n", err_code);
    return;
  }

  // Start Join procedure
  lmh_join();
}

void loop()
{
  // Put your application tasks here, like reading of sensors,
  // Controlling actuators and/or other functions. 
}

/**@brief LoRa function for handling HasJoined event.
 */
void lorawan_has_joined_handler(void)
{
  if(doOTAA == true)
  {
  Serial.println("OTAA Mode, Network Joined!");
  }
  else
  {
    Serial.println("ABP Mode");
  }

  lmh_error_status ret = lmh_class_request(gCurrentClass);
  if (ret == LMH_SUCCESS)
  {
    delay(1000);
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}
/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void)
{
  Serial.println("OTAA join failed!");
  Serial.println("Check your EUI's and Keys's!");
  Serial.println("Check if a Gateway is in range!");
}
/**@brief Function for handling LoRaWan received data from Gateway
 *
 * @param[in] app_data  Pointer to rx data
 */
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
          app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
  // Informs the server that switch has occurred ASAP
  m_lora_app_data.buffsize = 0;
  m_lora_app_data.port = gAppPort;
  lmh_send(&m_lora_app_data, gCurrentConfirm);
}

void send_lora_frame(void)
{
  if (lmh_join_status_get() != LMH_SET)
  {
    //Not joined, try again later
    return;
  }

  lmh_error_status error = lmh_send(&m_lora_app_data, gCurrentConfirm);
  if (error == LMH_SUCCESS)
  {
    count++;
    Serial.printf("lmh_send ok count %d\n", count);
  }
  else
  {
    count_fail++;
    Serial.printf("lmh_send fail count %d\n", count_fail);
  }
  TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
  TimerStart(&appTimer);
}

/**@brief Function for analytical direction.
 */
void direction_parse(String tmp)
{
    if (tmp.indexOf(",E,") != -1)
    {
        direction_E_W = 0;
    }
    else
    {
        direction_E_W = 1;
    }
    
    if (tmp.indexOf(",S,") != -1)
    {
        direction_S_N = 0;
    }
    else
    {
        direction_S_N = 1;
    }
}

/**@brief Function for handling a LoRa tx timer timeout event.
 */
String data = "";
void tx_lora_periodic_handler(void)
{ 
  float x = 0;
  float y = 0;
  float z = 0;

  bool newData = false;
  
  Serial.println("check acc!");
  x = SensorTwo.readFloatAccelX() * 1000;
  y = SensorTwo.readFloatAccelY() * 1000;
  z = SensorTwo.readFloatAccelZ() * 1000;
  data = "X = " + String(x) + "mg" + " Y = " + String(y) + "mg" + " Z =" + String(z) + "mg";
  Serial.println(data);
  data = "";
  if( abs(x-z) < 400)
  {
    // For one second we parse GPS data and report some key values
    for (unsigned long start = millis(); millis() - start < 1000;)
    {
      while (Serial1.available())
      {
        char c = Serial1.read();
//         Serial.write(c); // uncomment this line if you want to see the GPS data flowing
        tmp_data += c;
        if (gps.encode(c))// Did a new valid sentence come in?
          newData = true;
      }
    }
    direction_parse(tmp_data);
    tmp_data = "";
    float flat, flon;
    int32_t ilat, ilon;
    if (newData)
    {
      unsigned long age;  
      gps.f_get_position(&flat, &flon, &age);
      flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat;
      ilat = flat * 100000;
      flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon;
      ilon = flon * 100000;
      memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
      m_lora_app_data.port = gAppPort;
      m_lora_app_data.buffer[0] = 0x09;
      //lat data
      m_lora_app_data.buffer[1] = (ilat & 0xFF000000) >> 24;
      m_lora_app_data.buffer[2] = (ilat & 0x00FF0000) >> 16;
      m_lora_app_data.buffer[3] = (ilat & 0x0000FF00) >> 8;
      m_lora_app_data.buffer[4] =  ilat & 0x000000FF;
      if(direction_S_N == 0)
      {
        m_lora_app_data.buffer[5] = 'S';    
      }
      else
      {
        m_lora_app_data.buffer[5] = 'N';    
      }
      //lon data
      m_lora_app_data.buffer[6] = (ilon & 0xFF000000) >> 24;
      m_lora_app_data.buffer[7] = (ilon & 0x00FF0000) >> 16;
      m_lora_app_data.buffer[8] = (ilon & 0x0000FF00) >> 8;
      m_lora_app_data.buffer[9] =  ilon & 0x000000FF;
      if(direction_E_W == 0)
      {
        m_lora_app_data.buffer[10] = 'E';
      }
      else
      {
        m_lora_app_data.buffer[10] = 'W';
      }
      m_lora_app_data.buffsize = 11;
      send_lora_frame();
    }
    else
    {
      Serial.println("No Location Found");
      TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
      TimerStart(&appTimer);
    }
  }
  else
  {
    Serial.println("Turn WisBlock with USB pointing up to start location search");
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}

/**@brief Function for the Timer initialization.
 *
 * @details Initializes the timer module. This creates and starts application timers.
 */
uint32_t timers_init(void)
{
  TimerInit(&appTimer, tx_lora_periodic_handler);
  return 0;
}

Second Code

/**
 * @file GPS_Tracker.ino
 * @author rakwireless.com
 * @brief This sketch demonstrate a GPS tracker that collect location from a uBlox M7 GNSS sensor
 *    and send the data to lora gateway.
 *    It uses a 3-axis acceleration sensor to detect movement of the tracker
 * @version 0.2
 * @date 2021-04-30
 * 
 * @copyright Copyright (c) 2020
 * 
 * @note RAK4631 GPIO mapping to nRF52840 GPIO ports
   RAK4631    <->  nRF52840
   WB_IO1     <->  P0.17 (GPIO 17)
   WB_IO2     <->  P1.02 (GPIO 34)
   WB_IO3     <->  P0.21 (GPIO 21)
   WB_IO4     <->  P0.04 (GPIO 4)
   WB_IO5     <->  P0.09 (GPIO 9)
   WB_IO6     <->  P0.10 (GPIO 10)
   WB_SW1     <->  P0.01 (GPIO 1)
   WB_A0      <->  P0.04/AIN2 (AnalogIn A2)
   WB_A1      <->  P0.31/AIN7 (AnalogIn A7)
 */

#include <Arduino.h>
#include <LoRaWan-RAK4630.h> //http://librarymanager/All#SX126x
#include <SPI.h>
#include "SparkFunLIS3DH.h" //http://librarymanager/All#SparkFun-LIS3DH
#include "Wire.h"
#include <TinyGPS.h>        //http://librarymanager/All#TinyGPS
#include "SparkFun_SHTC3.h"   // Click here to get the library: http://librarymanager/All#SparkFun_SHTC3

LIS3DH SensorTwo(I2C_MODE, 0x18);

TinyGPS gps;

String tmp_data = "";
int direction_S_N = 0;  //0--S, 1--N
int direction_E_W = 0;  //0--E, 1--W

// RAK4630 supply two LED
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = true;   // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60                     /**< Maximum number of events in the scheduler queue. */
#define LORAWAN_DATERATE DR_0                   /*LoRaMac datarates definition, from DR_0 to DR_5*/
#define LORAWAN_TX_POWER TX_POWER_5             /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/
#define JOINREQ_NBTRIALS 3                      /**< Number of trials for the join request. */
DeviceClass_t gCurrentClass = CLASS_A;          /* class definition*/
LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_US915;    /* Region:EU868*/
lmh_confirm gCurrentConfirm = LMH_UNCONFIRMED_MSG;          /* confirm/unconfirm packet definition*/
uint8_t gAppPort = LORAWAN_APP_PORT;                      /* data port*/

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
 */
static lmh_param_t lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF};

// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                        lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler
                                       };
                                       
//OTAA keys !!!! KEYS ARE MSB !!!!


// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64                     /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 10000                        /**< Defines for user timer, the application data transmission interval. 10s, value in [ms]. */
static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];        //< Lora user application data buffer.
static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t appTimer;
static uint32_t timers_init(void);
static uint32_t count = 0;
static uint32_t count_fail = 0;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Initialize Serial for debug output
  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }

  // Initialize LoRa chip.
  lora_rak4630_init();

  Serial.println("=====================================");
  Serial.println("Welcome to RAK4630 LoRaWan!!!");
  if (doOTAA)
  {
    Serial.println("Type: OTAA");
  }
  else
  {
    Serial.println("Type: ABP");
  }

  switch (gCurrentRegion)
  {
    case LORAMAC_REGION_AS923:
      Serial.println("Region: AS923");
      break;
    case LORAMAC_REGION_AU915:
      Serial.println("Region: AU915");
      break;
    case LORAMAC_REGION_CN470:
      Serial.println("Region: CN470");
      break;
  case LORAMAC_REGION_CN779:
    Serial.println("Region: CN779");
    break;
    case LORAMAC_REGION_EU433:
      Serial.println("Region: EU433");
      break;
    case LORAMAC_REGION_IN865:
      Serial.println("Region: IN865");
      break;
    case LORAMAC_REGION_EU868:
      Serial.println("Region: EU868");
      break;
    case LORAMAC_REGION_KR920:
      Serial.println("Region: KR920");
      break;
    case LORAMAC_REGION_US915:
      Serial.println("Region: US915");
    break;
  case LORAMAC_REGION_RU864:
    Serial.println("Region: RU864");
    break;
  case LORAMAC_REGION_AS923_2:
    Serial.println("Region: AS923-2");
    break;
  case LORAMAC_REGION_AS923_3:
    Serial.println("Region: AS923-3");
    break;
  case LORAMAC_REGION_AS923_4:
    Serial.println("Region: AS923-4");
      break;
  }
  Serial.println("=====================================");

  //lis3dh init
  if (SensorTwo.begin() != 0)
  {
    Serial.println("Problem starting the sensor at 0x18.");
  }
  else
  {
    Serial.println("Sensor at 0x18 started.");
  // Set low power mode
  uint8_t data_to_write = 0;
  SensorTwo.readRegister(&data_to_write, LIS3DH_CTRL_REG1);
  data_to_write |= 0x08;
  SensorTwo.writeRegister(LIS3DH_CTRL_REG1, data_to_write);
  delay(100);

  data_to_write = 0;
  SensorTwo.readRegister(&data_to_write, 0x1E);
  data_to_write |= 0x90;
  SensorTwo.writeRegister(0x1E, data_to_write);
  delay(100);
  }
  //gps init

  pinMode(WB_IO2, OUTPUT);
  digitalWrite(WB_IO2, 0);
  delay(1000);
  digitalWrite(WB_IO2, 1);
  delay(1000);
  
  Serial1.begin(9600);
  while (!Serial1);
  Serial.println("gps uart init ok!");
  
  //creat a user timer to send data to server period
  uint32_t err_code;

  err_code = timers_init();
  if (err_code != 0)
  {
    Serial.printf("timers_init failed - %d\n", err_code);
    return;
  }

  // Setup the EUIs and Keys
  if (doOTAA)
  {
    lmh_setDevEui(nodeDeviceEUI);
    lmh_setAppEui(nodeAppEUI);
    lmh_setAppKey(nodeAppKey);
  }
  else
  {
    lmh_setNwkSKey(nodeNwsKey);
    lmh_setAppSKey(nodeAppsKey);
    lmh_setDevAddr(nodeDevAddr);
  }

  // Initialize LoRaWan
  err_code = lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion);
  if (err_code != 0)
  {
    Serial.printf("lmh_init failed - %d\n", err_code);
    return;
  }

  // Start Join procedure
  lmh_join();
}

void loop()
{
  // Put your application tasks here, like reading of sensors,
  // Controlling actuators and/or other functions. 
}

/**@brief LoRa function for handling HasJoined event.
 */
void lorawan_has_joined_handler(void)
{
  if(doOTAA == true)
  {
  Serial.println("OTAA Mode, Network Joined!");
  }
  else
  {
    Serial.println("ABP Mode");
  }

  lmh_error_status ret = lmh_class_request(gCurrentClass);
  if (ret == LMH_SUCCESS)
  {
    delay(1000);
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}
/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void)
{
  Serial.println("OTAA join failed!");
  Serial.println("Check your EUI's and Keys's!");
  Serial.println("Check if a Gateway is in range!");
}
/**@brief Function for handling LoRaWan received data from Gateway
 *
 * @param[in] app_data  Pointer to rx data
 */
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
          app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
  // Informs the server that switch has occurred ASAP
  m_lora_app_data.buffsize = 0;
  m_lora_app_data.port = gAppPort;
  lmh_send(&m_lora_app_data, gCurrentConfirm);
}

void send_lora_frame(void)
{
  if (lmh_join_status_get() != LMH_SET)
  {
    //Not joined, try again later
    return;
  }

  lmh_error_status error = lmh_send(&m_lora_app_data, gCurrentConfirm);
  if (error == LMH_SUCCESS)
  {
    count++;
    Serial.printf("lmh_send ok count %d\n", count);
  }
  else
  {
    count_fail++;
    Serial.printf("lmh_send fail count %d\n", count_fail);
  }
  TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
  TimerStart(&appTimer);
}

/**@brief Function for analytical direction.
 */
void direction_parse(String tmp)
{
    if (tmp.indexOf(",E,") != -1)
    {
        direction_E_W = 0;
    }
    else
    {
        direction_E_W = 1;
    }
    
    if (tmp.indexOf(",S,") != -1)
    {
        direction_S_N = 0;
    }
    else
    {
        direction_S_N = 1;
    }
}

/**@brief Function for handling a LoRa tx timer timeout event.
 */
String data = "";
void tx_lora_periodic_handler(void)
{ 
  float x = 0;
  float y = 0;
  float z = 0;

  bool newData = false;
  
  Serial.println("check acc!");
  x = SensorTwo.readFloatAccelX() * 1000;
  y = SensorTwo.readFloatAccelY() * 1000;
  z = SensorTwo.readFloatAccelZ() * 1000;
  data = "X = " + String(x) + "mg" + " Y = " + String(y) + "mg" + " Z =" + String(z) + "mg";
  Serial.println(data);
  data = "";
  if( abs(x-z) < 400)
  {
    // For one second we parse GPS data and report some key values
    for (unsigned long start = millis(); millis() - start < 1000;)
    {
      while (Serial1.available())
      {
        char c = Serial1.read();
         Serial.write(c); // uncomment this line if you want to see the GPS data flowing
        tmp_data += c;
        if (gps.encode(c))// Did a new valid sentence come in?
          newData = true;
      }
    }
    direction_parse(tmp_data);
    tmp_data = "";
    float flat, flon;
    int32_t ilat, ilon;
    if (newData)
    {
      unsigned long age;  
      gps.f_get_position(&flat, &flon, &age);
      flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat;
      ilat = flat * 100000;
      Serial.println('Latitude', ilat);
      flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon;
      ilon = flon * 100000;
      Serial.println('Longitude', ilon);
      memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
      m_lora_app_data.port = gAppPort;
      m_lora_app_data.buffer[0] = 0x09;
      //lat data
      m_lora_app_data.buffer[1] = (ilat & 0xFF000000) >> 24;
      m_lora_app_data.buffer[2] = (ilat & 0x00FF0000) >> 16;
      m_lora_app_data.buffer[3] = (ilat & 0x0000FF00) >> 8;
      m_lora_app_data.buffer[4] =  ilat & 0x000000FF;
      if(direction_S_N == 0)
      {
        m_lora_app_data.buffer[5] = 'S';    
      }
      else
      {
        m_lora_app_data.buffer[5] = 'N';    
      }
      //lon data
      m_lora_app_data.buffer[6] = (ilon & 0xFF000000) >> 24;
      m_lora_app_data.buffer[7] = (ilon & 0x00FF0000) >> 16;
      m_lora_app_data.buffer[8] = (ilon & 0x0000FF00) >> 8;
      m_lora_app_data.buffer[9] =  ilon & 0x000000FF;
      if(direction_E_W == 0)
      {
        m_lora_app_data.buffer[10] = 'E';
      }
      else
      {
        m_lora_app_data.buffer[10] = 'W';
      }
      m_lora_app_data.buffsize = 11;
      send_lora_frame();
    }
    else
    {
      Serial.println("No Location Found");
      TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
      TimerStart(&appTimer);
    }
  }
  else
  {
    Serial.println("Turn WisBlock with USB pointing up to start location search");
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}

/**@brief Function for the Timer initialization.
 *
 * @details Initializes the timer module. This creates and starts application timers.
 */
uint32_t timers_init(void)
{
  TimerInit(&appTimer, tx_lora_periodic_handler);
  return 0;
}

I’ve had it standing vertically for 20 minutes and did the gps debug example to see what was going on and never get coordinates it does seem to be communicating to the chip though
image

When it says configure, does that only have to be done once outside then it will work indoors or it only works outdoors?