This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

LTE-M always connected

Shalom!

 I have using the nRF9160 examples created an application for a future proposed custom board that when there is external power should always stay connected to our TCP server in LTE-M mode.

Like in the UDP example main.c file, I call modem_init(), configure_low_power() & then modem_connect().

After LTE-M network connection, I connect to our TCP server successfully but then I get a RRC change to Idle notification and then no TCP server requests are received.

We have another project using a different modem that connects to the LTE-M network that is always accessible in external power mode.

I tried changing the the proj.conf file fields and also lte_lc_psm_req(false);

The same board will need to use the LTE-M's power saving modes when only a battery is connected.

How can I have the nFR9160 always connected without going to idle?

What am I doing wrong?

This is the first time I have had to address the PSM & RPTAU & RAT directly.

Thanks

  • Hi! Apologies for the late reply.

    Could you please take a modem trace when this is happening so we can have a closer look?

    See Collecting a modem trace for the nRF9160 DK

    Best regards,

    Heidi

  • trace-2021-06-10T03-19-46.258Z_CONFIG_PM_DEVICE=y.bintrace-2021-06-10T03-26-57.987Z_CONFIG_PM_DEVICE=n.bin

    Shalom!

    0167.prj.conf

    Shalom!

     I took two traces, one with CONFIG_PM_DEVICE=y and the other CONFIG_PM_DEVICE=n.

    The modem connects to the cellular network and then my application connects by TCP to my Application server and after a few seconds of inactivity the modem goes to RRC Idle.

    I also attached my proj.c0181.nrf9160dk_nrf9160ns.overlayonf file. Our custom nRF9160 board contains a AT24C512 EEPROM, a LSM6DSL acceleration chip, a SI7055 temperature chip and a mx25r6435 external flash.

    I created an overlay just in preparation for the board's arrival adding the chips to existing buses but when the config are enabled I get compile errors. Evidently I am doing something wrong or missing something in my overlay.

    Thanks

     David

  • Hi!

    Can I see your main.c and Kconfig file as well, to understand what the configurations do? 

    I see 

    CONFIG_GPS_CONTROL_PSM_ENABLE_ON_START

    is enabled which could mean you are still enabling PSM on startup.


    You can try sending AT+CPSMS after start-up to see if PSM is enabled.

    Best regards,
    Heidi

  • Shalom!

    We will use the GPS in one software version, so I was testing it, without success, maybe because of obstructions, but in any case the define is remarked in the proj.cong file when testing always our connected work mode. I will attached our main with irrelevant functions deleted and again my ami_socket.c TCP code.

    Thanks David

    2072.prj.conf

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <stdio.h>
    #include <modem/lte_lc.h>
    #include <net/socket.h>
    #include <device.h>
    #include <drivers/sensor.h>
    #include <drivers/gps.h>
    #include <drivers/uart.h>
    #include <date_time.h>
    #include <time.h>
    
    
    #if defined(CONFIG_WATCHDOG_APPLICATION)
    #include "watchdog.h"
    #endif
    
    #if defined(CONFIG_BOOTLOADER_MCUBOOT)
    #include <dfu/mcuboot.h>
    #endif
    
    #include <logging/log.h>
    #include <logging/log_ctrl.h>
    #include "aqua_def.h"
    #include "ami_GPS.h"
    #include "gps_controller.h"
    
    
    #ifdef TBD
             ---------------------------------------------------------
              --- WARNING: Using default MCUBoot key, it should not ---
              --- be used for production.                           ---
              ---------------------------------------------------------
    #endif
     
    // nRF9160 DK (PCA10090)
    // Thingy:91, you have to use the nrf9160_pca20035 
    //
    
    //-----------------------------------------------------------------------------
    // Last Updated
    //-----------------------------------------------------------------------------
    const char* LastUpdate ={"16-Jun-2021"};
    
    /* Module name is used by the event manager macros in this file */
    #define MODULE app_module
    
    LOG_MODULE_REGISTER(MODULE, CONFIG_APPLICATION_MODULE_LOG_LEVEL);
    
    //-----------------------------------------------------------------------------
    // Stack definition for application workqueue 
    //-----------------------------------------------------------------------------
    K_THREAD_STACK_DEFINE(application_stack_area,
    		      CONFIG_APPLICATION_WORKQUEUE_STACK_SIZE);
    static struct k_work_q application_work_q;
    
    static struct k_delayed_work seconds_work;
    #if defined(CONFIG_DATE_TIME)
    static s64_t  unix_time_ms = 0;
    #endif
    
    
    K_SEM_DEFINE(lte_connected, 0, 1);
    
    //-----------------------------------------------------------------------------
    // seconds_work_fn
    //  Description
    //    Worker that wakes up every second
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    static void seconds_work_fn(struct k_work *work)
    {
      static uint8_t secs = 0;
      //---------------------------------------------------------------------------
      // Another second has passed
      //---------------------------------------------------------------------------
      secsFrom2004.ulong++;
      state.iNewSec     = 0xFFFF;
      state.bRTCRunning = TRUE;
      secs++;
      //---------------------------------------------------------------------------
      // Another minute has passed
      //---------------------------------------------------------------------------
      if (secs>=60){
        secs = 0;
        state.iNewMinute = 0xFFFF;
      }
      k_delayed_work_submit(&seconds_work,K_SECONDS(1));
    } // seconds_work_fn
    
    //-----------------------------------------------------------------------------
    // ami_main_ModemRegistered
    //  Description
    //    Tries to send the binary data over the connection
    //  Parameters
    //  Returns
    //   
    //-----------------------------------------------------------------------------
    bool ami_main_ModemRegistered(void)
    {
      enum lte_lc_nw_reg_status status;
      //---------------------------------------------------------------------------
      // Returns zero if call is successful
      //---------------------------------------------------------------------------
      if (!lte_lc_nw_reg_status_get(&status)){
       if (status==LTE_LC_NW_REG_REGISTERED_HOME || status==LTE_LC_NW_REG_REGISTERED_ROAMING){
         return true;
        }
      }
      return false;
    } // ami_main_ModemRegistered
    
    //-----------------------------------------------------------------------------
    // work_init
    //  Description
    //    Inits all workers
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    static void work_init(void)
    {
      k_delayed_work_init(&seconds_work,seconds_work_fn);                      
    } // work_init
    
    //-----------------------------------------------------------------------------
    // lte_handler
    //  Description
    //    modem event handler
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    #if defined(CONFIG_NRF_MODEM_LIB)
    static void lte_handler(const struct lte_lc_evt *const evt)
    {
      switch (evt->type) {
        case LTE_LC_EVT_NW_REG_STATUS:
          if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) &&
              (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) {
            break;
          }
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"NetworkRegStatus:Connected%s",
                  evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ?
                  "Home" : "Roaming");
          k_sem_give(&lte_connected);
          break;
        case LTE_LC_EVT_PSM_UPDATE:
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"PSMupdate TAU:%d ActiveTime:%d",
                  evt->psm_cfg.tau, evt->psm_cfg.active_time);
          break;
        case LTE_LC_EVT_EDRX_UPDATE: 
          {
            char log_buf[60];
            ssize_t len;
    
            len = snprintf(log_buf, sizeof(log_buf),"eDRXupdate eDRX:%f PTW:%f",
                           evt->edrx_cfg.edrx, evt->edrx_cfg.ptw);
            if (len>0){
              d_printf(LINE_INFO,kDbg_Info|kDbg_General,"%s", log_buf);
            }
          }
          break;
        case LTE_LC_EVT_RRC_UPDATE:
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"RRC mode:%s",
                  evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ?
                  "Connected" : "Idle");
          break;
        case LTE_LC_EVT_CELL_UPDATE:
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"LTE cellchange CellID:%d TrackingArea:%d",
                 evt->cell.id, evt->cell.tac);
          break;
        default:
          break;
      } // switch
    } // lte_handler
    
    //-----------------------------------------------------------------------------
    // ami_main_switch_low_power
    //  Description
    //    Configures low power
    //  Parameters
    //    bSwToLowPower true to switch to lower power
    //  Returns
    //-----------------------------------------------------------------------------
    static int ami_main_switch_low_power(bool bSwToLowPower)
    {
      int err;
    
      //---------------------------------------------------------------------------
      // Switch to Low power modem mode?
      //---------------------------------------------------------------------------
      if (bSwToLowPower){
        err = lte_lc_psm_req(true);
        if (err) {
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"lte_lc_psm_req err:%d", err);
        }
      }else{
    	err = lte_lc_psm_req(false);
    	if (err) {
              d_printf(LINE_INFO,kDbg_Info|kDbg_General,"lte_lc_psm_req err:%d", err);
    	}
      }
    
    #if defined(CONFIG_AMI_EDRX_ENABLE)
      /** enhanced Discontinuous Reception */
      err = lte_lc_edrx_req(true);
      if (err) {
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"lte_lc_edrx_req err:%d", err);
      }
    #else
      err = lte_lc_edrx_req(false);
      if (err) {
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"lte_lc_edrx_req err: %d", err);
      }
    #endif
    
    #if defined(CONFIG_AMI_RAI_ENABLE)
      /** Release Assistance Indication  */
      err = lte_lc_rai_req(true);
      if (err) {
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"lte_lc_rai_req, err:%d", err);
      }
    #endif
      return err;
    } // ami_main_switch_low_power
    
    //-----------------------------------------------------------------------------
    // modem_init
    //  Description
    //    Inits Modem
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    static void modem_init(void)
    {
      //---------------------------------------------------------------------------
      // Int and connect automatically?
      //---------------------------------------------------------------------------
      if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
        //-------------------------------------------------------------------------
        // Do nothing, modem is already configured and LTE connected. 
        //-------------------------------------------------------------------------
      }else{
            int err = lte_lc_init();
            if (err) {
              d_printf(LINE_INFO,kDbg_Info|kDbg_General,"ModemInitFailErr:%d", err);
            }
      }
    } // modem_init
    
    //-----------------------------------------------------------------------------
    // ami_main_modem_connect
    //  Description
    //    Trys to connect the modem to the LTE network
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_main_modem_connect(void)
    {
      //---------------------------------------------------------------------------
      // Int and connect automatically?
      //---------------------------------------------------------------------------
      if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
        //-------------------------------------------------------------------------
        // Do nothing, modem is already configured and LTE connected. 
        //-------------------------------------------------------------------------
      }else{
            int err = lte_lc_connect_async(lte_handler);
            if (err) {
              d_printf(LINE_INFO,kDbg_Error|kDbg_General,"Connecting LTE network Err:%d",err);
            }
      }
    } // ami_main_modem_connect
    #endif
    
    
    //-----------------------------------------------------------------------------
    // ami_main_Init
    //  Description
    //   StandAlone and Master mode main initialization
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    bool ami_main_Init(void)
    {
      //---------------------------------------------------------------------------
      // Variables init
      //---------------------------------------------------------------------------
      memset(&state,0,sizeof(state));
      memset(&otap_info,0,sizeof(otap_info));
      memset(&point_state,0,sizeof(point_state));
      memset(&alert_state,0,sizeof(alert_state));
      memset(&schd_state,0,sizeof(schd_state));
      //---------------------------------------------------------------------------
      //---------------------------------------------------------------------------
      // Configuration files init
      //---------------------------------------------------------------------------
      if (cfg_read_Config()){
        //-------------------------------------------------------------------------
        // problem with configuration
        //-------------------------------------------------------------------------
        ami_Scheduler_RaiseGeneralAlert(AQUA_ALERT_GEN_INDEX_CONFIG);
      }
      //---------------------------------------------------------------------------
      // Watchdog reset? Currently does not detect Watchdog reset!
      //---------------------------------------------------------------------------
      if (gResetInfo){
        ami_Scheduler_RaiseGeneralAlert(AQUA_ALERT_GEN_INDEX_WATCHDOG);
      }
    #if defined(CONFIG_NRF9160_GPS)
      //---------------------------------------------------------------------------
      // GPS Init
      //---------------------------------------------------------------------------
      ami_GPSInit(&application_work_q);
    #endif
      //---------------------------------------------------------------------------
      // Finished startup
      //---------------------------------------------------------------------------
      state.bFinishedStartup = TRUE;
      return TRUE;
    } // ami_main_Init
    
    
    //-----------------------------------------------------------------------------
    // ami_main_Loop
    //  Description
    //   StandAlone and Master modes main loop
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_main_Loop(void)
    {
      //---------------------------------------------------------------------------
      // Main new second
      //---------------------------------------------------------------------------
      if (state.iNewSec & AQUA_CLK_TASK_MASK_MAIN){
        state.iNewSec &= ~AQUA_CLK_TASK_MASK_MAIN;
        ami_main_SecHandler();
      }
      //---------------------------------------------------------------------------
      // Main new Minute
      //---------------------------------------------------------------------------
      if (state.iNewMinute & AQUA_CLK_TASK_MASK_MAIN){
        state.iNewMinute &= ~AQUA_CLK_TASK_MASK_MAIN;
        ami_main_MinuteHandler();
      }
    #if defined(CONFIG_NRF9160_GPS)
      //---------------------------------------------------------------------------
      // Service GPS
      //---------------------------------------------------------------------------
      if (ami_GPSIsActive()){
        ami_GPS_Service();
      }
    #endif
    } // ami_main_Loop
    
    //-----------------------------------------------------------------------------
    // main
    //  Description
    //    Main program
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    void main(void)
    {
      int err;
    
      //---------------------------------------------------------------------------
      // Init Watchdog
      //---------------------------------------------------------------------------
    #if defined(CONFIG_WATCHDOG_APPLICATION)
      err = watchdog_init_and_start();
      if (err) {
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"watchdog_init_and_start, error: %d", err);
        // SEND_ERROR(app, APP_EVT_ERROR, err);
      }
    #endif
      //---------------------------------------------------------------------------
      // Init and start work queue
      //---------------------------------------------------------------------------
      k_work_q_start(&application_work_q, application_stack_area,
                     K_THREAD_STACK_SIZEOF(application_stack_area),
                     CONFIG_APPLICATION_WORKQUEUE_PRIORITY);
      //---------------------------------------------------------------------------
      // Init Work tasks
      //---------------------------------------------------------------------------
      work_init();
      //---------------------------------------------------------------------------
      // Init Modem
      //---------------------------------------------------------------------------
      d_printf(LINE_INFO,kDbg_Info|kDbg_General,"ModemInit");
      //---------------------------------------------------------------------------
      // Init main
      //---------------------------------------------------------------------------
      ami_main_Init();
    #if defined(CONFIG_NRF_MODEM_LIB)
      //---------------------------------------------------------------------------
      // Initialize the modem before calling ami_main_switch_low_power(). This is
      //  because the enabling of RAI is dependent on the
      //  configured network mode which is set during modem initialization.
      //---------------------------------------------------------------------------
      modem_init();
      //---------------------------------------------------------------------------
      // Configure low power
      //---------------------------------------------------------------------------
      err = ami_main_switch_low_power(true);
      if (err) {
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"Unable to set low power configuration, error: %d\n",
                     err);
      }
      //---------------------------------------------------------------------------
      // nRF9160 modem init
      //---------------------------------------------------------------------------
      ami_main_modem_connect();
      k_sem_take(&lte_connected, K_FOREVER);
    #endif
      //---------------------------------------------------------------------------
      // Init periodic second worker task
      //---------------------------------------------------------------------------
      k_delayed_work_submit(&seconds_work,K_SECONDS(1));
      //---------------------------------------------------------------------------
      // Init AMI Socket
      //---------------------------------------------------------------------------
      ami_socket_init();
      //---------------------------------------------------------------------------
      // Main Loop
      //---------------------------------------------------------------------------
      for (;;){
        ami_main_Loop(); 
        k_sleep(K_MSEC(1));
      }
    } // main
    
    /*
     * Copyright (c) 2017 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    #include <zephyr.h>
    #include <stdio.h>
    #include <modem/lte_lc.h>
    #include <net/socket.h>
    #include <device.h>
    #include <drivers/sensor.h>
    #include <date_time.h>
    #include <time.h>
    
    //#include <logging/log.h>
    //#include <logging/log_ctrl.h>
    #include "aqua_def.h"
    #include "ami_main.h"
    #include "ami_socket.h"
    #include "d_printf.h"
    #include "ami_modem.h"
    
    #define RECV_BUF_SIZE 576
    #define CONFIG_DOWNLOAD_CLIENT_TCP_SOCK_TIMEO_MS 30000
    #define CONFIG_DOWNLOAD_CLIENT_UDP_SOCK_TIMEO_MS 4000
    
    /* Validates if the API was requested in the right state. */
    #define NOT_VALID_STATE(EXPECTED) ((EXPECTED) < cur_socket_state)
    
    //-----------------------------------------------------------------------------
    // Maintains the state with respect to the cloud. 
    //-----------------------------------------------------------------------------
    static volatile enum ami_socket_state cur_socket_state = AMI_SOCKET_STATE_IDLE;
    
    //-----------------------------------------------------------------------------
    // Flag to indicate if a disconnect has been requested. 
    //-----------------------------------------------------------------------------
    static atomic_t disconnect_requested;
    
    //-----------------------------------------------------------------------------
    // Flag to indicate if a transport disconnect event has been received. 
    //-----------------------------------------------------------------------------
    static atomic_t transport_disconnected;
    
    // static struct cloud_backend *nrf_cloud_backend;
    
    /* Handler registered by the application with the module to receive
     * asynchronous events.
     */
    static ami_socket_event_handler_t app_event_handler;
    static char                        recv_buf[RECV_BUF_SIZE];
    
    
    static K_MUTEX_DEFINE(state_mutex);
    
    static K_SEM_DEFINE(connection_poll_sem, 0, 1);
    static atomic_t connection_poll_active;
    static int      app_socket_fd = -1;
    
    
    //-----------------------------------------------------------------------------
    // Local Function Prototypes
    //-----------------------------------------------------------------------------
    
    //-----------------------------------------------------------------------------
    // ami_socket_get_current_state
    //  Description
    //    
    //  Parameters
    //  Returns
    //   Current State
    //-----------------------------------------------------------------------------
    enum ami_socket_state ami_socket_get_current_state(void)
    {
      return cur_socket_state;
    } // ami_socket_get_current_state
    
    //-----------------------------------------------------------------------------
    // ami_socket_set_current_state_and_notify
    //  Description
    //    
    //  Parameters
    //   state
    //   evt
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_socket_set_current_state_and_notify(enum ami_socket_state state,
    				       const struct ami_socket_evt *evt)
    {
      k_mutex_lock(&state_mutex, K_FOREVER);
      cur_socket_state = state;
    
      if ((evt != NULL) &&
          (evt->type == AMI_SOCKET_EVT_TRANSPORT_DISCONNECTED)) {
        atomic_set(&transport_disconnected, 1);
      }
    
      if ((app_event_handler != NULL) && (evt != NULL)) {
        app_event_handler(evt);
      }
      k_mutex_unlock(&state_mutex);
    } // ami_socket_set_current_state_and_notify
    
    //-----------------------------------------------------------------------------
    // ami_socket_get_disconnect_requested
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    bool ami_socket_get_disconnect_requested(void)
    {
      return (bool)atomic_get(&disconnect_requested);
    } // ami_socket_get_disconnect_requested
    
    #ifdef TBD
    //-----------------------------------------------------------------------------
    // connect_error_translate
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int connect_error_translate(const int err)
    {
      switch (err) {
        case 0:
                return AMI_SOCKET_CONNECT_RES_SUCCESS;
        case -ECHILD:
                return AMI_SOCKET_CONNECT_RES_ERR_NETWORK;
        case -EACCES:
                return AMI_SOCKET_CONNECT_RES_ERR_NOT_INITD;
        case -ENOEXEC:
                return AMI_SOCKET_CONNECT_RES_ERR_BACKEND;
        case -EINVAL:
                return AMI_SOCKET_CONNECT_RES_ERR_PRV_KEY;
        case -EOPNOTSUPP:
                return AMI_SOCKET_CONNECT_RES_ERR_CERT;
        case -ECONNREFUSED:
                return AMI_SOCKET_CONNECT_RES_ERR_CERT_MISC;
        case -ETIMEDOUT:
                return AMI_SOCKET_CONNECT_RES_ERR_TIMEOUT_NO_DATA;
        case -ENOMEM:
                return AMI_SOCKET_CONNECT_RES_ERR_NO_MEM;
        case -EINPROGRESS:
                return AMI_SOCKET_CONNECT_RES_ERR_ALREADY_CONNECTED;
        default:
                // LOG_ERR("nRF cloud connect failed %d", err);
                return AMI_SOCKET_CONNECT_RES_ERR_MISC;
      } // switch
    } // connect_error_translate
    #endif
    
    //-----------------------------------------------------------------------------
    // inet_addr
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    u32_t inet_addr(u8_t a, u8_t b, u8_t c, u8_t d)
    {
      u32_t value = 0;
    
      value |= (u32_t)((((u8_t)(d)) << 24) & 0xFF000000);
      value |= (u32_t)((((u8_t)(c)) << 16) & 0x00FF0000);
      value |= (u32_t)((((u8_t)(b)) << 8) & 0x0000FF00);
      value |= (u32_t)((((u8_t)(a)) << 0) & 0x000000FF);
      return value;
    } // inet_addr
    
    //-----------------------------------------------------------------------------
    // blocking_recv
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int blocking_recv(int fd, u8_t *buf, u32_t size, u32_t flags)
    {
      int err;
    
      do{
         err = recv(fd, buf, size, flags);
      }while ((err<0) && (errno==EAGAIN) && !ami_socket_get_disconnect_requested());
      return err;
    } // blocking_recv
    
    //-----------------------------------------------------------------------------
    // blocking_send
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    static int blocking_send(int fd, u8_t *buf, u32_t size, u32_t flags)
    {
      int err;
    
      do{
         err = send(fd, buf, size, flags);
      }while ((err<0) && (errno==EAGAIN) && !ami_socket_get_disconnect_requested());
      return err;
    } // blocking_send
    
    //-----------------------------------------------------------------------------
    // ami_socket_SendBinaryData
    //  Description
    //    Tries to send the binary data over the connection
    //  Parameters
    //    buf
    //    len
    //  Returns
    //    true if sent
    //-----------------------------------------------------------------------------
    bool ami_socket_SendBinaryData(const unsigned char *buf,uint16_t len)
    {
      int err = blocking_send(app_socket_fd,(u8_t *)buf, len, 0);
      if (err < 0) {
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"TX Fail:%d", errno);
    //#ifdef TBD
        //---------------------------------------------------------------------
        // Set Network Disconnected 
        //---------------------------------------------------------------------
        struct ami_socket_evt evt;
        evt.type   = AMI_SOCKET_EVT_TRANSPORT_DISCONNECTED;
        evt.status = AMI_SOCKET_CONNECT_RES_ERR_NETWORK;
        ami_socket_set_current_state_and_notify(AMI_SOCKET_STATE_DISCONNECTED, &evt);
    //#endif
      }
      return (err==0);
    } // ami_socket_SendBinaryData
    
    //-----------------------------------------------------------------------------
    // blocking_connect
    //  Description
    //    
    //  Parameters
    //  Returns
    //   0 = OK
    //-----------------------------------------------------------------------------
    static int blocking_connect(int fd, struct sockaddr *local_addr, socklen_t len)
    {
      int err;
    
      do{
         err = connect(fd, local_addr, len);
      }while ((err<0) && (errno==EAGAIN) && !ami_socket_get_disconnect_requested());
      return err;
    } // blocking_connect
    
    //-----------------------------------------------------------------------------
    // socket_timeout_set
    //  Description
    //    
    //  Parameters
    //  Returns
    //   0 = OK
    //-----------------------------------------------------------------------------
    static int socket_timeout_set(int fd, int type)
    {
      int err;
      uint32_t timeout_ms;
    
      if (type == SOCK_STREAM) {
        timeout_ms = CONFIG_DOWNLOAD_CLIENT_TCP_SOCK_TIMEO_MS;
      }else{
            timeout_ms = CONFIG_DOWNLOAD_CLIENT_UDP_SOCK_TIMEO_MS;
      }
    
      if (timeout_ms <= 0) {
        return 0;
      }
    
      struct timeval timeo = {
        .tv_sec = (timeout_ms / 1000),
        .tv_usec = (timeout_ms % 1000) * 1000,
      };
    
      d_printf(LINE_INFO,kDbg_Info|kDbg_General,"SocketTimeout:%lds", timeo.tv_sec);
      err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
      if (err){
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"SocketTimeoutErr:%d", errno);
        return -errno;
      }
    #ifdef TBD
      int enable = 1;
      err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
      if (err<0){
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"setsockopt(SO_REUSEADDR) failed");
      }
     #endif
      return 0;
    } // socket_timeout_set
    
    //-----------------------------------------------------------------------------
    // connect_to_cloud
    //  Description
    //    Tries to connect to the Cloud
    //  Parameters
    //  Returns
    //   ami_socket_connect_result
    //-----------------------------------------------------------------------------
    static int connect_to_cloud(void)
    {
      atomic_set(&disconnect_requested, 0);
    
      struct sockaddr    local_addr;
      int                err;
      char               sIPPort[24];
    
      sprintf(sIPPort,"%u.%u.%u.%u:%u",
          cur_server.server_ip.bytes[MSB_HI_BYTE],
          cur_server.server_ip.bytes[MSB_LO_BYTE],
          cur_server.server_ip.bytes[LSB_HI_BYTE],
          cur_server.server_ip.bytes[LSB_LO_BYTE],
          cur_server.server_port.word
       );
      //---------------------------------------------------------------------------
      // Parse the IP:Port string
      //---------------------------------------------------------------------------
      if (!net_ipaddr_parse((const char *)sIPPort,strlen(sIPPort),&local_addr)){
        d_printf(LINE_INFO,kDbg_Error|kDbg_General,"ServerIP:PortParsingErr");
        return AMI_SOCKET_CONNECT_RES_ERR_NOT_INITD;
      }
      //---------------------------------------------------------------------------
      // Close socket if opened
      //---------------------------------------------------------------------------
      if (app_socket_fd>=0){
        close(app_socket_fd);
      }
      //---------------------------------------------------------------------------
      // Create a TCP socket
      //---------------------------------------------------------------------------
      app_socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
      d_printf(LINE_INFO,kDbg_Info|kDbg_General,"SocketFD:%d",app_socket_fd);
      //---------------------------------------------------------------------------
      // Set socket timeout
      //---------------------------------------------------------------------------
      err = socket_timeout_set(app_socket_fd,SOCK_STREAM);
      if (err) {
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"SetSockTimeoutErr:%d", errno);
        return err;
      }
      //---------------------------------------------------------------------------
      // Connect
      //---------------------------------------------------------------------------
      err = blocking_connect(app_socket_fd, (struct sockaddr *)&local_addr,sizeof(struct sockaddr_in));
      if (errno){
        err = errno;
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"ConnectionErr:%d %s",errno,sIPPort);
      }else
        d_printf(LINE_INFO,kDbg_Info|kDbg_General,"Connected:%s",sIPPort);
      return err;
    } // connect_to_cloud
    
    //-----------------------------------------------------------------------------
    // ami_socket_disconnect
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int ami_socket_disconnect(void)
    {
      if (NOT_VALID_STATE(AMI_SOCKET_STATE_CONNECTED)) {
        return -EACCES;
      }
      atomic_set(&disconnect_requested, 1);
      return 0;
    } // ami_socket_disconnect
    
    //-----------------------------------------------------------------------------
    // ami_socket_start_connection_poll
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int ami_socket_start_connection_poll()
    {
      //---------------------------------------------------------------------------
      // IDLE?
      //---------------------------------------------------------------------------
      if (cur_socket_state==AMI_SOCKET_STATE_IDLE) {
        return -EACCES;
      }
      //---------------------------------------------------------------------------
      // Already Connected?
      //---------------------------------------------------------------------------
      if (cur_socket_state==AMI_SOCKET_STATE_CONNECTED){
        return 0;
      }
      if (atomic_get(&connection_poll_active)) {
        // LOG_DBG("Connection poll in progress");
        return -EINPROGRESS;
      }
      atomic_set(&disconnect_requested, 0);
      k_sem_give(&connection_poll_sem);
      return 0;
    } // ami_socket_start_connection_poll
    
    //-----------------------------------------------------------------------------
    // ami_socket_internal_init
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int ami_socket_internal_init(const struct ami_socket_init_param *param)
    {
      if (cur_socket_state != AMI_SOCKET_STATE_IDLE) {
        return -EACCES;
      }
      if (param->event_handler == NULL) {
        return -EINVAL;
      }
      //---------------------------------------------------------------------------
      // Set Event handler
      //---------------------------------------------------------------------------
      app_event_handler = param->event_handler;
      //---------------------------------------------------------------------------
      // Set state
      //---------------------------------------------------------------------------
      cur_socket_state = AMI_SOCKET_STATE_INITIALIZED;
      return 0;
    } // ami_socket_internal_init
    
    //-----------------------------------------------------------------------------
    // api_event_handler
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    static void api_event_handler(const struct ami_socket_evt *evt)
    {
      static int8_t kkk = 0;
      if (evt!=NULL){
        kkk++;
      }
      switch (evt->type){
        case AMI_SOCKET_EVT_TRANSPORT_CONNECTING:
          break;
        case AMI_SOCKET_EVT_TRANSPORT_CONNECTED:
          MODEM_TCP_UDPConnected(true);
          break;
        case AMI_SOCKET_EVT_RX_DATA:
          {
            NRF9160_OnlineRXMsg((unsigned char *)evt->data.ptr,evt->data.len);
          }
          break;
        case AMI_SOCKET_EVT_TRANSPORT_DISCONNECTED:
          MODEM_TCP_UDPConnected(false);
          break;
        default:
          break;
      } // switch
    } // api_event_handler
    
    //-----------------------------------------------------------------------------
    // ami_socket_init
    //  Description
    //    
    //  Parameters
    //  Returns
    //
    //-----------------------------------------------------------------------------
    int ami_socket_init(void)
    {
      const struct ami_socket_init_param params = {
              .event_handler = api_event_handler
      };
      return ami_socket_internal_init(&params);
    } // ami_socket_init
    
    //-----------------------------------------------------------------------------
    // ami_socket_run
    //  Description
    //    
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_socket_run(int unused1, int unused2, int unused3)
    {
      int                   ret;
      struct ami_socket_evt evt;
    
    start:
      k_sem_take(&connection_poll_sem, K_FOREVER);
      atomic_set(&connection_poll_active, 1);
    
      evt.type = AMI_SOCKET_EVT_TRANSPORT_CONNECTING;
      evt.status = AMI_SOCKET_CONNECT_RES_SUCCESS;
      app_event_handler(&evt);
    
      //---------------------------------------------------------------------------
      // Connect to Cloud
      //---------------------------------------------------------------------------
      ret = connect_to_cloud(); 
      //---------------------------------------------------------------------------
      // Translate error
      //---------------------------------------------------------------------------
     // ret = connect_error_translate(ret);
      //---------------------------------------------------------------------------
      // Connection error?
      //---------------------------------------------------------------------------
      if (ret != AMI_SOCKET_CONNECT_RES_SUCCESS) {
        if (ret==-ECONNREFUSED){
          d_printf(LINE_INFO,kDbg_Info|kDbg_General,"Connected:%s",ret); 
        }
        goto reset;
      }
      //---------------------------------------------------------------------------
      // Set Connected 
      //---------------------------------------------------------------------------
      evt.type  = AMI_SOCKET_EVT_TRANSPORT_CONNECTED;
      evt.status = AMI_SOCKET_CONNECT_RES_SUCCESS;
      ami_socket_set_current_state_and_notify(AMI_SOCKET_STATE_CONNECTED, &evt);
      //---------------------------------------------------------------------------
      // Clear 
      //---------------------------------------------------------------------------
      atomic_set(&transport_disconnected, 0);
      //---------------------------------------------------------------------------
      // Loop
      //---------------------------------------------------------------------------
      while (true) {
        size_t reply_bytes;
        do {
            if (ami_socket_get_disconnect_requested()){
              evt.type   = AMI_SOCKET_EVT_TRANSPORT_DISCONNECTED;
              evt.status = AMI_SOCKET_DISCONNECT_MISC;
              ami_socket_set_current_state_and_notify(AMI_SOCKET_STATE_DISCONNECTED, &evt);
              goto reset;
            }
            reply_bytes = blocking_recv(app_socket_fd, recv_buf,sizeof(recv_buf)-1,0);
            if (reply_bytes > 0 && ret < RECV_BUF_SIZE) {
              evt.type = AMI_SOCKET_EVT_RX_DATA;
              evt.data.ptr = (char *)recv_buf;
              evt.data.len = reply_bytes;
              app_event_handler(&evt);
            }
    #ifdef TBD
            //---------------------------------------------------------------------
            // Disconnected
            //---------------------------------------------------------------------
            if (atomic_get(&transport_disconnected) == 1) {
              evt.type   = AMI_SOCKET_EVT_TRANSPORT_DISCONNECTED;
              evt.status = AMI_SOCKET_DISCONNECT_MISC;
              goto reset;
            }
    #endif
            k_sleep(K_MSEC(4));
       } while (reply_bytes > 0);
       //--------------------------------------------------------------------------
       // Send the event if the transport has not already been disconnected 
       //--------------------------------------------------------------------------
       if (atomic_get(&transport_disconnected) == 0) {
         app_event_handler(&evt);
         ami_socket_disconnect(); 
         break;
       }
     } // while
    
    reset:
      //---------------------------------------------------------------------------
      // Close socket if opened
      //---------------------------------------------------------------------------
      if (app_socket_fd>=0){
        close(app_socket_fd);
        app_socket_fd = -1;
      }
      atomic_set(&disconnect_requested, 0);
      atomic_set(&connection_poll_active, 0);
     // k_sem_take(&connection_poll_sem, K_NO_WAIT);
      k_sleep(K_MSEC(5000));
      goto start;
    } // ami_socket_run
    
    #define POLL_THREAD_PRIORITY 5      // K_LOWEST_APPLICATION_THREAD_PRIO
    #define POLL_THREAD_STACK_SIZE 3072
    K_THREAD_DEFINE(connection_poll_thread, POLL_THREAD_STACK_SIZE,
    		ami_socket_run, NULL, NULL, NULL,
    		POLL_THREAD_PRIORITY, 0, 0);
    
    

Related