Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Libuarte and GPS

Hello everyone,

I ran into an issue where I just can't get my head around.

I followed the Libuarte example, and I thought I modified it "correctly" to fit my application where I am connected to a GPS device emitting a number of messages every second.

I was able to correctly receive the data from the GPS and write it to a variable, but I run into either an NRF_BUSY, NRF_SUCCESS or NRF_NO_MEM error or sometimes into a hard fault error when I try and send a command to the unit. (it has the form of uint8_t RMC[] = "$PCAS03,0,0,0,0,1,0,0,0,0,0,,,0,0*03\r\n" - so there must be something I am missing and doing wrong.

Could someone please help me with an example of the uart_event_handler to correctly receive the output from the device( and possible how to look for a specific message in the output) and how to send commands to the device from somewhere else in the code.

Currently, my uart_event handler looks like this:

NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);


typedef struct {
    uint8_t * p_data;
    uint32_t length;
} buffer_t;

NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);


uint8_t uart0_array[500]; //buffer to copy uart data to

void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    static uint8_t index = 0;
    switch(p_evt->type)
    { 
      case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
      {
          sprintf(uart0_array,"%s",p_evt->data.rxtx.p_data);
            
          nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
      }break;
      case NRF_LIBUARTE_ASYNC_EVT_ERROR:
      {
          //printf("\nUART ERROR: %d", p_evt->data.errorsrc);
      }break;
      case NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR:
      {
          //printf("\nUART OVERRUN ERROR");
      }break;
      
    }
}

And I am able to see the data in uart0_array but it obviously overflows since I don't do any processing on it now.

When I used this code with a device that does not emit every second that caused the errors, I was able to send over UART with the following function I used:

//Function to send via UART
void send_UART(char *sdata, int len)
{
  for (int i = 0; i < len; i++)
  {
    ret_code_t ret;
    ret = nrf_libuarte_async_tx(&libuarte, &sdata[i], 1);
    
    APP_ERROR_CHECK(ret);
    nrf_delay_ms(1);
  }
}

But this does not work with the GPS as it causes anyone of that errors. I tried to increase the timeout of the Uart as well but to no avail.



So to recap:

I require help/examples of how to send a typical command like "$PCAS03,0,0,0,0,1,0,0,0,0,0,,,0,0*03\r\n" to the GPS device over UART, and receive a typical message like follows every second

$GNRMC,164352.97,V,,,,,,,060421,,,N,V*11
$GNGGA,164352.97,,,,,0,04,8.0,,M,,M,,*7D
$GNGLL,,,,,164352.97,V,N*5D
$GPGSV,16,,,31,26,,,20,27,,,32,1*6D

where I would for instance only want to save the "$GNGLL,,,,,164352.97,V,N*5D" message so if you can help me to only extract a message that starts with for instance $GNGLL and ends with /r/n that would be a bonus and great, and I would forever be thankful for your help.


Any help would be appreciated.

Thank you for your time.

Kind regards,

Darius

Parents
  • Hi,

    Why do you send the data one and one byte at a time?

    You should be able to write the full TX buffer like this:

    //Function to send via UART
    void send_UART(char *sdata, int len)
    {
        ret_code_t ret;
        ret = nrf_libuarte_async_tx(&libuarte, sdata, len);
        
        APP_ERROR_CHECK(ret);
    }

    Note that you can only start a single transfer at a time, if there is already an ongoing transfer, you will get the NRF_ERROR_BUSY return code. 

    You can use a do-while to do a blocking wait for the previous transfer to finish:

    //Function to send via UART
    void send_UART(char *sdata, int len)
    {
        ret_code_t ret;
        do {
            ret = nrf_libuarte_async_tx(&libuarte, sdata, len);
        while (ret == NRF_ERROR_BUSY);
        
        APP_ERROR_CHECK(ret);
    }

    Not sure where you get the NRF_ERROR_NO_MEM return code from, this does not seem to be a valid return code from the nrf_libuarte_drv_tx() function. 

    To look for a substring in a string, you can use strstr() function. Note that the string function may take long time to process, you should consider doing this outside of the interrupt/event handler, to allow other interrupts to be handled while processing strings.

    Best regards,
    Jørgen

  • Thank you, Jorgen, that worked:)

    Is there a way to handle the data up to the "\n" character? so that it keeps filling the uart0_array[] with the data from the GPS until the "/n" character is reached and then break or copy the whole string to another buffer so I can process it?

    Because I tried the following (sprintf() and memcpy()) and get the string up to "/n" but after3-4 seconds I get a HardFault_Handler: error.


    NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 5);
    
    
    typedef struct {
        uint8_t * p_data;
        uint32_t length;
    } buffer_t;
    //NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);
    NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);
    
    
    uint8_t uart0_array[500]; //buffer to copy uart data to
    
    
    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        
        static uint8_t data_array[100];
        static uint16_t index = 0;
        
        switch(p_evt->type)
        { 
          case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
          {
            strcat(data_array,p_evt->data.rxtx.p_data);
            index++;
    
          if ((data_array[index] == '\n') ||
              (data_array[index - 1] == '\r'))
          {
    
              //memcpy(uart0_array,data_array,sizeof(data_array));
              sprintf(uart0_array, "%s", data_array);
              nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                
    
    
              index = 0;
          }
    
    
              //sprintf(byte,"%s",p_evt->data.rxtx.p_data);
              //strcat(uart0_array,p_evt->data.rxtx.p_data);
              
              //nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
          }break;
          case NRF_LIBUARTE_ASYNC_EVT_ERROR:
          {
              //printf("\nUART ERROR: %d", p_evt->data.errorsrc);
          }break;
          case NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR:
          {
              //printf("\nUART OVERRUN ERROR");
          }break;
          
        }
    }


    Thanks for your help so far.

Reply
  • Thank you, Jorgen, that worked:)

    Is there a way to handle the data up to the "\n" character? so that it keeps filling the uart0_array[] with the data from the GPS until the "/n" character is reached and then break or copy the whole string to another buffer so I can process it?

    Because I tried the following (sprintf() and memcpy()) and get the string up to "/n" but after3-4 seconds I get a HardFault_Handler: error.


    NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 5);
    
    
    typedef struct {
        uint8_t * p_data;
        uint32_t length;
    } buffer_t;
    //NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);
    NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);
    
    
    uint8_t uart0_array[500]; //buffer to copy uart data to
    
    
    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        
        static uint8_t data_array[100];
        static uint16_t index = 0;
        
        switch(p_evt->type)
        { 
          case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
          {
            strcat(data_array,p_evt->data.rxtx.p_data);
            index++;
    
          if ((data_array[index] == '\n') ||
              (data_array[index - 1] == '\r'))
          {
    
              //memcpy(uart0_array,data_array,sizeof(data_array));
              sprintf(uart0_array, "%s", data_array);
              nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                
    
    
              index = 0;
          }
    
    
              //sprintf(byte,"%s",p_evt->data.rxtx.p_data);
              //strcat(uart0_array,p_evt->data.rxtx.p_data);
              
              //nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
          }break;
          case NRF_LIBUARTE_ASYNC_EVT_ERROR:
          {
              //printf("\nUART ERROR: %d", p_evt->data.errorsrc);
          }break;
          case NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR:
          {
              //printf("\nUART OVERRUN ERROR");
          }break;
          
        }
    }


    Thanks for your help so far.

Children
Related