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

How to achieve the lowest power consumption on the Actinius Icarus (nrf9160) board?

Hi,

I'm trying to lower the power consumption om an Actinius Icarus board which uses an nrf9160 chip. I've been able to achieve a sleep current of 1.33mA and I'm not able to lower this any further. Could you please let me know what else I could do to lower the power consumption?

My setup - 

  • Board - Actinius Icarus
  • NRF Connect SDK - v1.2.0
  • Modem FW - 1.1.1
  • Sim - External NBIoT Sim card from 1nce which uses Deutsche Telekom band 8
  • Antenna - Ethertronics penta 1002292
  • Input - 4x1.5V batteries supplied to the Vin pin
  • Current measurement - Multimeter inserted between batteries and Vin
  • External peripherals - Using a 10k NTC with a 10k pullup voltage divider circuit connected to A1 for temperature measurement

Things done to reduce power consumption - 

  1. Disabled logs in the project and SPM- 
    CONFIG_CONSOLE=n
    CONFIG_STDOUT_CONSOLE=n
    CONFIG_LOG=n
    CONFIG_SERIAL=n
    CONFIG_UART_CONSOLE=n

  2. Enabled power management - 
    CONFIG_SYS_POWER_MANAGEMENT=y
    CONFIG_DEVICE_POWER_MANAGEMENT=y

  3. Enabled PSM with these parameters (Also with different p-tau like 10 min, 1 hour, etc) 
    CONFIG_LTE_PSM_REQ_RPTAU="11000001"
    CONFIG_LTE_PSM_REQ_RAT="00000001"

  4. Removed bootloader - 
    CONFIG_BOOTLOADER_MCUBOOT=n

The current drawn through the NTC voltage divider is around .16mA. I have connected to the AWS server via MQTT and send sensor data to the server at a fixed interval. I send the data and go to sleep for a defined time and repeat the process. I observe a constant sleep current of 1.3mA. When the device wakes up and sends data, I see spikes of 50mA and it comes back to 1.3mA after 2 seconds according to CONFIG_LTE_PSM_REQ_RAT.
For testing, I also edited the same project and made the device run an infinite while loop with a sleep function and still see that the sleep current is 1.3mA. From what I understand it looks like the modem does go to PSM (if I disable it I see a sleep current which keeps fluctuating between 1.3mA to 50mA). The sleep current with the modem switched off (with an AT+CFUN=0) command also shows me a sleep current of 1.3mA. This leads me to believe that there are some other peripherals which are switched on and consuming power. I'm not able to figure what else I should be doing at this point to lower the current consumption. Could you please advise me on  how to proceed? Thanks a lot!
Nikil
Parents
  • # Logs
    CONFIG_CONSOLE=n
    CONFIG_STDOUT_CONSOLE=n
    CONFIG_LOG=n
    CONFIG_SERIAL=n
    CONFIG_UART_CONSOLE=n
    CONFIG_BSD_LIBRARY_TRACE_ENABLED=n
    
    # Peripherals
    CONFIG_ADC=y
    CONFIG_ADC_0=y
    CONFIG_ADC_1=y
    CONFIG_ADC_NRFX_SAADC=y
    CONFIG_GPIO=y
    
    # TEE
    CONFIG_TRUSTED_EXECUTION_NONSECURE=y
    
    # Bootloader - Application update support
    CONFIG_BOOTLOADER_MCUBOOT=n
    
    # Networking
    CONFIG_NETWORKING=y
    CONFIG_NET_NATIVE=n
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    # BSD library
    CONFIG_BSD_LIBRARY=y
    
    # LTE link control
    CONFIG_LTE_LINK_CONTROL=y
    CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
    CONFIG_LTE_NETWORK_MODE_NBIOT=y
    CONFIG_LTE_LINK_CONTROL_LOG_LEVEL_DBG=y
    
    # AT Host
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_AT_HOST_LIBRARY=y
    
    # external sim 
    CONFIG_BOARD_SELECT_SIM_EXTERNAL=y
    
    # power mgmt
    CONFIG_SYS_POWER_MANAGEMENT=y
    CONFIG_DEVICE_POWER_MANAGEMENT=y
    
    #AWS
    CONFIG_AWS_IOT=y
    CONFIG_AWS_IOT_BROKER_HOST_NAME="a26a1lpxwnwowb-ats.iot.eu-central-1.amazonaws.com"
    CONFIG_AWS_IOT_SEC_TAG=75316842
    CONFIG_AWS_IOT_LOG_LEVEL_DBG=y
    CONFIG_AWS_IOT_CLIENT_ID_APP=y
    CONFIG_MQTT_LOG_LEVEL_DBG=y
    
    # Main thread
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_LTE_PSM_REQ_RPTAU="11000001"
    CONFIG_LTE_PSM_REQ_RAT="00000010"
    CONFIG_MQTT_KEEPALIVE=1200
    
    CONFIG_HEAP_MEM_POOL_SIZE=16384
    

    /**
     * @file main.c
     * @author Nikil Rao ([email protected])
     * @brief
     * @version 0.1
     * @date 2020-03-31
     *
     * @copyright Copyright (c) 2020
     *
     */
    
    /*=============================================================================
     *                                 Includes
     *==============================================================================*/
    #include "tempSensor.h"
    #include <at_cmd.h>
    #include <at_cmd_parser/at_cmd_parser.h>
    #include <at_cmd_parser/at_params.h>
    #include <at_notif.h>
    #include <drivers/gpio.h>
    #include <lte_lc.h>
    #include <net/aws_iot.h>
    #include <net/mqtt.h>
    #include <net/socket.h>
    #include <nrf_socket.h>
    #include <stdio.h>
    #include <string.h>
    #include <zephyr.h>
    
    /*=============================================================================
     *                             Defines
     *==============================================================================*/
    #define BUFFER_SIZE                   10
    #define IMEI_LEN                      20
    #define DEV_ID_LEN                    20
    #define RED_LED                       DT_ALIAS_LED0_GPIOS_PIN
    #define LED_ON                        0
    #define LED_OFF                       !LED_ON
    #define DEVICE_SLEEP_INTERVAL         330 // 330 seconds works 333 doesn't
    #define DEVICE_AWAKE_INTERVAL         4 // 2 seconds works
    #define AT_CESQ_RESPONSE_PREFIX       "+CESQ"
    #define AT_CESQ_PARAMS_COUNT_MAX      7
    #define AT_CESQ_RESPONSE_PREFIX_INDEX 0
    #define AT_CESQ_RESPONSE_RSRQ_INDEX   5
    #define AT_CESQ_RESPONSE_RSRP_INDEX   6
    /*=============================================================================
     *                             Static Variables
     *==============================================================================*/
    /* Connected flag */
    static bool connected               = false;
    static char dev_id[DEV_ID_LEN]      = {0};
    static struct device *gpio_dev      = {0};
    static struct aws_iot_config config = {0};
    static struct pollfd fds            = {0};
    
    /*=============================================================================
     *                             Private Functions
     *==============================================================================*/
    
    /**
     * @brief Configures modem to provide LTE link. Blocks until link is
     * successfully established.
     *
     */
    static void modem_configure(void)
    {
        int err;
        // Use static IP as there was some problem resolving DNS
        struct nrf_in_addr dns;
        dns.s_addr = 134744072; // Google DNS, 8.8.8.8
        err        = nrf_setdnsaddr(2, &dns);
        printk("Set DNS Address (%d)\r\n", err);
    
    #if defined(CONFIG_LTE_LINK_CONTROL)
        if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT))
        {
            /* Do nothing, modem is already turned on
             * and connected.
             */
        }
        else
        {
            int err;
    
            printk("LTE Link Connecting ...\n");
            err = lte_lc_init_and_connect();
            __ASSERT(err == 0, "LTE link could not be established.");
            printk("LTE Link Connected!\n");
        }
    #endif /* defined(CONFIG_LTE_LINK_CONTROL) */
    }
    
    /*=============================================================================*/
    
    /**
     * @brief Set up Power Saving Mode for the modem
     *        Refer PSM.md for info on the values
     *
     */
    void modem_setup_psm(void)
    {
        /*
         * GPRS Timer 3 value (octet 3)
         *
         * Bits 5 to 1 represent the binary coded timer value.
         *
         * Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
         * Bits
         * 8 7 6
         * 0 0 0 value is incremented in multiples of 10 minutes
         * 0 0 1 value is incremented in multiples of 1 hour
         * 0 1 0 value is incremented in multiples of 10 hours
         * 0 1 1 value is incremented in multiples of 2 seconds
         * 1 0 0 value is incremented in multiples of 30 seconds
         * 1 0 1 value is incremented in multiples of 1 minute
         * 1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
         * 1 1 1 value indicates that the timer is deactivated (NOTE 2).
         */
        char psm_settings[] = CONFIG_LTE_PSM_REQ_RPTAU;
    
        printk("PSM bits: %c%c%c\n", psm_settings[0], psm_settings[1],
               psm_settings[2]);
        printk("PSM Interval: %c%c%c%c%c\n", psm_settings[3], psm_settings[4],
               psm_settings[5], psm_settings[6], psm_settings[7]);
    
        int err = lte_lc_psm_req(true);
        if (err < 0)
        {
            printk("Error setting PSM: %d Errno: %d\n", err, errno);
        }
    }
    
    /*=============================================================================*/
    /**
     * @brief 
     * <rsrq>
        0 rsrq < −19.5 dB
        1 – When −19.5 dB ≤ RSRQ < −19 dB
        2 – When −19 dB ≤ RSRQ < −18.5 dB
        ...
        32 – When −4 dB ≤ RSRQ < −3.5 dB
        33 – When −3.5 dB ≤ RSRQ < −3 dB
        34 – When −3 dB ≤ RSRQ
        255 – Not known or not detectable
        rsrq
        >= -10 dB	Excellent	Strong signal with maximum data speeds
        -10 dB to -15 dB	Good	Strong signal with good data speeds
        -15 dB to -20 dB	Fair to poor	Reliable data speeds may be attained, but marginal data with drop-outs is possible. When this value gets close to -20, performance will drop drastically
        <= -20 dB	No signal	Disconnection
    
        <rsrp>
        0 – RSRP < −140 dBm
        1 – When −140 dBm ≤ RSRP < −139 dBm
        2 – When −139 dBm ≤ RSRP < −138 dBm
        ...
        95 – When −46 dBm ≤ RSRP < −45 dBm
        96 – When −45 dBm ≤ RSRP < −44 dBm
        97 – When −44 dBm ≤ RSRP
        255 – Not known or not detectable
        rsrp
        >= -80 dBm	Excellent	Strong signal with maximum data speeds
        -80 dBm to -90 dBm	Good	Strong signal with good data speeds
        -90 dBm to -100 dBm	Fair to poor	Reliable data speeds may be attained, but marginal data with drop-outs is possible. When this value gets close to -100, performance will drop drastically
        <= -100 dBm	No signal	Disnonnection
     * @param rsrp 
     * @param rsrq 
     * @return int 
     */
    int modem_getSignalStrength(s16_t *rsrp, s16_t *rsrq)
    {
        int err;
        enum at_cmd_state at_state;
        char buf[32];
        uint32_t value;
        struct at_param_list resp_list = {0};
    
        char response_prefix[sizeof(AT_CESQ_RESPONSE_PREFIX)] = {0};
        size_t response_prefix_len = sizeof(response_prefix);
    
        if ((err = at_cmd_write("AT+CESQ", buf, sizeof(buf), &at_state)))
        {
            printk("Error when trying to do at_cmd_write: %d, at_state: %d\n", err,
                   at_state);
            return err;
        }
        printf("%s\n", buf);
    
        if ((err = at_params_list_init(&resp_list, AT_CESQ_PARAMS_COUNT_MAX)))
        {
            printk("Could not init AT params list, error: %d\n", err);
            return err;
        }
    
        /* Parse CESQ response and populate AT parameter list */
    
        if ((err = at_parser_max_params_from_str(buf, NULL, &resp_list,
                                                 AT_CESQ_PARAMS_COUNT_MAX)))
        {
            printk("Could not parse AT+CESQ response, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
    
        /* Check if AT command response starts with +CESQ */
        if ((err = at_params_string_get(&resp_list, AT_CESQ_RESPONSE_PREFIX_INDEX,
                                        response_prefix, &response_prefix_len)))
        {
            printk("Could not get response prefix, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
    
        if (strncmp(response_prefix, AT_CESQ_RESPONSE_PREFIX, response_prefix_len))
        {
            /* The unsolicited response is not a CESQ response, ignore it.
             */
            printk("String not matching %s\n", response_prefix);
            at_params_list_free(&resp_list);
            return err;
        }
    
        if ((err =
                 at_params_int_get(&resp_list, AT_CESQ_RESPONSE_RSRQ_INDEX, &value)) != 0)
        {
            printk("Could not get RSRQ: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
        *rsrq = (s16_t)value;
    
        if ((err =
                 at_params_int_get(&resp_list, AT_CESQ_RESPONSE_RSRP_INDEX, &value)) != 0)
        {
            printk("Could not get RSRP, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
        *rsrp = (s16_t)value;
    
        at_params_list_free(&resp_list);
        return err;
    }
    
    /*=============================================================================*/
    
    int device_getDevID()
    {
        int err;
        enum at_cmd_state at_state;
        char imei_buf[IMEI_LEN + 5];
    
        if ((err = at_cmd_write("AT+CGSN", imei_buf, IMEI_LEN + 5, &at_state)))
        {
            printk("Error when trying to do at_cmd_write: %d, at_state: %d", err,
                   at_state);
            return err;
        }
    
        snprintf(dev_id, 20, "nrf-%s", imei_buf);
        return err;
    }
    
    /*=============================================================================*/
    
    /**
     * @brief Handle events sent from AWS MQTT server
     *
     * @param evt
     */
    void aws_iot_evt_handler(const struct aws_iot_evt *evt)
    {
        printk("aws_iot_evt_handler %d\r\n", evt->type);
    
        if (evt->type == AWS_IOT_EVT_READY)
        {
            connected = true;
            led_switchOff();
        }
    }
    
    /*=============================================================================*/
    
    int aws_init(void)
    {
        int err;
    
        device_getDevID();
        config.client_id     = dev_id;
        config.client_id_len = strlen(dev_id);
    
        if ((err = aws_iot_init(&config, aws_iot_evt_handler)) == 0)
        {
            printk("aws_iot_initialized\r\n");
        }
        else
        {
            printk("aws_iot_init failed: %d\n", err);
            return err;
        }
        return err;
    }
    
    /*=============================================================================*/
    
    void aws_connect(void)
    {
        int err;
        while ((err = aws_iot_connect(&config)) != 0)
        {
            printk("aws_iot_connect failed: %d\n", err);
            k_sleep(5000);
        }
    
        printk("aws_iot_connected\n");
        return;
    }
    
    /*=============================================================================*/
    
    void aws_reconnect(void)
    {
        int err;
        
        aws_iot_disconnect();
        aws_init();
        connected = false;
        led_switchOn();
        aws_connect();
        
        return;
    }
    
    /*=============================================================================*/
    
    /**
     * @brief
     *
     * @return int
     */
    static int aws_publish_data()
    {
        int err                     = 0;
        static uint32_t msg_counter = 0;
        float temperature           = 0;
        u16_t battery_voltage       = 0;
        s16_t rsrp                  = 0;
        s16_t rsrq                  = 0;
    
        tempSensor_getTemperature(&temperature);
        tempSensor_getBatteryVoltage(&battery_voltage);
        modem_getSignalStrength(&rsrp, &rsrq);
    
        /* Send data to topic */
        char topic_msg[256];
        sprintf(topic_msg,
                "{\"state\":{\"reported\":{\"device\":\"%s\", "
                "\"message_count\":\"%d\", "
                "\"temperature\":\"%.2f\", \"battery_level\":\"%d\", "
                "\"RSRQ\":\"%d\", \"RSRP\":\"%d\"}}}",
                dev_id, ++msg_counter, temperature, battery_voltage, rsrq, rsrp);
    
        char *topic_name = "concr/temperature";
    
        struct aws_iot_topic_data topic = {
            /** Type of shadow topic that will be published to. */
            // enum aws_iot_topic_type
            .type = AWS_IOT_SHADOW_TOPIC_UPDATE,
            /** Pointer to string of application specific topic. */
            // char *
            .str = topic_name,
            /** Length of application specific topic. */
            // size_t
            .len = strlen(topic_name),
        };
    
        const struct aws_iot_tx_data tx_data = {
            /** Topic that the message will be sent to. */
            // struct aws_iot_topic_data
            .topic = topic,
            /** Pointer to message to be sent to AWS IoT broker. */
            .str = topic_msg,
            /** Length of message. */
            .len = strlen(topic_msg),
            /** Quality of Service of the message. */
            .qos = 1,
        };
    
        if (aws_iot_send(&tx_data) != 0)
        {
            printk("Failed to publish sensor data\r\n");
        }
        else
        {
            printk("Publish Sensor Data\r\n");
            printk("DATA: %s\r\n", topic_msg);
        }
    
        return err;
    }
    
    /*=============================================================================*/
    
    void fds_init(void)
    {
        fds.fd     = config.socket;
        fds.events = POLLIN;
    }
    
    /*=============================================================================*/
    
    int led_init(void)
    {
        int err;
        gpio_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    
        if (!gpio_dev)
        {
            printk("Error getting " DT_GPIO_P0_DEV_NAME " device binding\r\n");
            err = 1;
            return err;
        }
    
        gpio_pin_configure(gpio_dev, RED_LED, GPIO_DIR_OUT);
        return err;
    }
    
    /*=============================================================================*/
    
    void led_switchOn(void) { gpio_pin_write(gpio_dev, RED_LED, LED_ON); }
    
    /*=============================================================================*/
    
    void led_switchOff(void) { gpio_pin_write(gpio_dev, RED_LED, LED_OFF); }
    
    
    /*=============================================================================*/
    
    /**
     * @brief
     *
     */
    void main(void)
    {
        printk("NRF9160 Temperature Sensor Started...!!!\r\n");
        int err;
    
        s64_t time_stamp     = k_uptime_get();
        s32_t delay_interval = K_SECONDS(DEVICE_SLEEP_INTERVAL);
        s32_t awake_interval = K_SECONDS(DEVICE_AWAKE_INTERVAL);
    
        led_init();
        led_switchOn();
        modem_configure();
        modem_setup_psm();
        tempSensor_init();
        aws_init();
        aws_connect();
        fds_init();
    
        printk("Initialized successfully in %lldms\n", k_uptime_delta(&time_stamp));
    
        while (true)
        {
            printk("\n");
    
            if(connected == false)
            {
                //Wait to be connected before publishing data
                delay_interval = 0;
                awake_interval = K_SECONDS(CONFIG_MQTT_KEEPALIVE);
            }
            else
            {
                //After connection publish data to thje AWS server
                delay_interval = K_SECONDS(DEVICE_SLEEP_INTERVAL);
                awake_interval = K_SECONDS(DEVICE_AWAKE_INTERVAL);
                aws_publish_data();
            }
            
            err = poll(&fds, 1, awake_interval);
    
            if (err < 0)
            {
                printk("poll() returned an error: %d\n", err);
                continue;
            }
            else if (err == 0)
            {
                if(aws_iot_keepalive_time_left() < 0)
                {
                    aws_iot_ping();
                    continue;
                }
            }        
    
            if ((fds.revents & POLLIN) == POLLIN)
            {
                aws_iot_input();
            }
    
            if ((fds.revents & POLLNVAL) == POLLNVAL)
            {
                printk("Socket error: POLLNVAL\n");
                printk("The AWS IoT socket was unexpectedly closed.\n");
                aws_reconnect();
                continue;
            }
    
            if ((fds.revents & POLLHUP) == POLLHUP)
            {
                printk("Socket error: POLLHUP\n");
                printk("Connection was closed by the AWS IoT broker.\n");
                aws_reconnect();
                continue;
            }
    
            if ((fds.revents & POLLERR) == POLLERR)
            {
                printk("Socket error: POLLERR\n");
                printk("AWS IoT broker connection was unexpectedly closed.\n");
                aws_reconnect();
                continue;
            }
    
            k_sleep(delay_interval);
        }   
    }
    /*=============================================================================
     *                             Public Functions
     *==============================================================================*/
    
    /*=============================================================================
     *                             End of File
     *==============================================================================*/
    

Reply
  • # Logs
    CONFIG_CONSOLE=n
    CONFIG_STDOUT_CONSOLE=n
    CONFIG_LOG=n
    CONFIG_SERIAL=n
    CONFIG_UART_CONSOLE=n
    CONFIG_BSD_LIBRARY_TRACE_ENABLED=n
    
    # Peripherals
    CONFIG_ADC=y
    CONFIG_ADC_0=y
    CONFIG_ADC_1=y
    CONFIG_ADC_NRFX_SAADC=y
    CONFIG_GPIO=y
    
    # TEE
    CONFIG_TRUSTED_EXECUTION_NONSECURE=y
    
    # Bootloader - Application update support
    CONFIG_BOOTLOADER_MCUBOOT=n
    
    # Networking
    CONFIG_NETWORKING=y
    CONFIG_NET_NATIVE=n
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    # BSD library
    CONFIG_BSD_LIBRARY=y
    
    # LTE link control
    CONFIG_LTE_LINK_CONTROL=y
    CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
    CONFIG_LTE_NETWORK_MODE_NBIOT=y
    CONFIG_LTE_LINK_CONTROL_LOG_LEVEL_DBG=y
    
    # AT Host
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_AT_HOST_LIBRARY=y
    
    # external sim 
    CONFIG_BOARD_SELECT_SIM_EXTERNAL=y
    
    # power mgmt
    CONFIG_SYS_POWER_MANAGEMENT=y
    CONFIG_DEVICE_POWER_MANAGEMENT=y
    
    #AWS
    CONFIG_AWS_IOT=y
    CONFIG_AWS_IOT_BROKER_HOST_NAME="a26a1lpxwnwowb-ats.iot.eu-central-1.amazonaws.com"
    CONFIG_AWS_IOT_SEC_TAG=75316842
    CONFIG_AWS_IOT_LOG_LEVEL_DBG=y
    CONFIG_AWS_IOT_CLIENT_ID_APP=y
    CONFIG_MQTT_LOG_LEVEL_DBG=y
    
    # Main thread
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_LTE_PSM_REQ_RPTAU="11000001"
    CONFIG_LTE_PSM_REQ_RAT="00000010"
    CONFIG_MQTT_KEEPALIVE=1200
    
    CONFIG_HEAP_MEM_POOL_SIZE=16384
    

    /**
     * @file main.c
     * @author Nikil Rao ([email protected])
     * @brief
     * @version 0.1
     * @date 2020-03-31
     *
     * @copyright Copyright (c) 2020
     *
     */
    
    /*=============================================================================
     *                                 Includes
     *==============================================================================*/
    #include "tempSensor.h"
    #include <at_cmd.h>
    #include <at_cmd_parser/at_cmd_parser.h>
    #include <at_cmd_parser/at_params.h>
    #include <at_notif.h>
    #include <drivers/gpio.h>
    #include <lte_lc.h>
    #include <net/aws_iot.h>
    #include <net/mqtt.h>
    #include <net/socket.h>
    #include <nrf_socket.h>
    #include <stdio.h>
    #include <string.h>
    #include <zephyr.h>
    
    /*=============================================================================
     *                             Defines
     *==============================================================================*/
    #define BUFFER_SIZE                   10
    #define IMEI_LEN                      20
    #define DEV_ID_LEN                    20
    #define RED_LED                       DT_ALIAS_LED0_GPIOS_PIN
    #define LED_ON                        0
    #define LED_OFF                       !LED_ON
    #define DEVICE_SLEEP_INTERVAL         330 // 330 seconds works 333 doesn't
    #define DEVICE_AWAKE_INTERVAL         4 // 2 seconds works
    #define AT_CESQ_RESPONSE_PREFIX       "+CESQ"
    #define AT_CESQ_PARAMS_COUNT_MAX      7
    #define AT_CESQ_RESPONSE_PREFIX_INDEX 0
    #define AT_CESQ_RESPONSE_RSRQ_INDEX   5
    #define AT_CESQ_RESPONSE_RSRP_INDEX   6
    /*=============================================================================
     *                             Static Variables
     *==============================================================================*/
    /* Connected flag */
    static bool connected               = false;
    static char dev_id[DEV_ID_LEN]      = {0};
    static struct device *gpio_dev      = {0};
    static struct aws_iot_config config = {0};
    static struct pollfd fds            = {0};
    
    /*=============================================================================
     *                             Private Functions
     *==============================================================================*/
    
    /**
     * @brief Configures modem to provide LTE link. Blocks until link is
     * successfully established.
     *
     */
    static void modem_configure(void)
    {
        int err;
        // Use static IP as there was some problem resolving DNS
        struct nrf_in_addr dns;
        dns.s_addr = 134744072; // Google DNS, 8.8.8.8
        err        = nrf_setdnsaddr(2, &dns);
        printk("Set DNS Address (%d)\r\n", err);
    
    #if defined(CONFIG_LTE_LINK_CONTROL)
        if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT))
        {
            /* Do nothing, modem is already turned on
             * and connected.
             */
        }
        else
        {
            int err;
    
            printk("LTE Link Connecting ...\n");
            err = lte_lc_init_and_connect();
            __ASSERT(err == 0, "LTE link could not be established.");
            printk("LTE Link Connected!\n");
        }
    #endif /* defined(CONFIG_LTE_LINK_CONTROL) */
    }
    
    /*=============================================================================*/
    
    /**
     * @brief Set up Power Saving Mode for the modem
     *        Refer PSM.md for info on the values
     *
     */
    void modem_setup_psm(void)
    {
        /*
         * GPRS Timer 3 value (octet 3)
         *
         * Bits 5 to 1 represent the binary coded timer value.
         *
         * Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
         * Bits
         * 8 7 6
         * 0 0 0 value is incremented in multiples of 10 minutes
         * 0 0 1 value is incremented in multiples of 1 hour
         * 0 1 0 value is incremented in multiples of 10 hours
         * 0 1 1 value is incremented in multiples of 2 seconds
         * 1 0 0 value is incremented in multiples of 30 seconds
         * 1 0 1 value is incremented in multiples of 1 minute
         * 1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
         * 1 1 1 value indicates that the timer is deactivated (NOTE 2).
         */
        char psm_settings[] = CONFIG_LTE_PSM_REQ_RPTAU;
    
        printk("PSM bits: %c%c%c\n", psm_settings[0], psm_settings[1],
               psm_settings[2]);
        printk("PSM Interval: %c%c%c%c%c\n", psm_settings[3], psm_settings[4],
               psm_settings[5], psm_settings[6], psm_settings[7]);
    
        int err = lte_lc_psm_req(true);
        if (err < 0)
        {
            printk("Error setting PSM: %d Errno: %d\n", err, errno);
        }
    }
    
    /*=============================================================================*/
    /**
     * @brief 
     * <rsrq>
        0 rsrq < −19.5 dB
        1 – When −19.5 dB ≤ RSRQ < −19 dB
        2 – When −19 dB ≤ RSRQ < −18.5 dB
        ...
        32 – When −4 dB ≤ RSRQ < −3.5 dB
        33 – When −3.5 dB ≤ RSRQ < −3 dB
        34 – When −3 dB ≤ RSRQ
        255 – Not known or not detectable
        rsrq
        >= -10 dB	Excellent	Strong signal with maximum data speeds
        -10 dB to -15 dB	Good	Strong signal with good data speeds
        -15 dB to -20 dB	Fair to poor	Reliable data speeds may be attained, but marginal data with drop-outs is possible. When this value gets close to -20, performance will drop drastically
        <= -20 dB	No signal	Disconnection
    
        <rsrp>
        0 – RSRP < −140 dBm
        1 – When −140 dBm ≤ RSRP < −139 dBm
        2 – When −139 dBm ≤ RSRP < −138 dBm
        ...
        95 – When −46 dBm ≤ RSRP < −45 dBm
        96 – When −45 dBm ≤ RSRP < −44 dBm
        97 – When −44 dBm ≤ RSRP
        255 – Not known or not detectable
        rsrp
        >= -80 dBm	Excellent	Strong signal with maximum data speeds
        -80 dBm to -90 dBm	Good	Strong signal with good data speeds
        -90 dBm to -100 dBm	Fair to poor	Reliable data speeds may be attained, but marginal data with drop-outs is possible. When this value gets close to -100, performance will drop drastically
        <= -100 dBm	No signal	Disnonnection
     * @param rsrp 
     * @param rsrq 
     * @return int 
     */
    int modem_getSignalStrength(s16_t *rsrp, s16_t *rsrq)
    {
        int err;
        enum at_cmd_state at_state;
        char buf[32];
        uint32_t value;
        struct at_param_list resp_list = {0};
    
        char response_prefix[sizeof(AT_CESQ_RESPONSE_PREFIX)] = {0};
        size_t response_prefix_len = sizeof(response_prefix);
    
        if ((err = at_cmd_write("AT+CESQ", buf, sizeof(buf), &at_state)))
        {
            printk("Error when trying to do at_cmd_write: %d, at_state: %d\n", err,
                   at_state);
            return err;
        }
        printf("%s\n", buf);
    
        if ((err = at_params_list_init(&resp_list, AT_CESQ_PARAMS_COUNT_MAX)))
        {
            printk("Could not init AT params list, error: %d\n", err);
            return err;
        }
    
        /* Parse CESQ response and populate AT parameter list */
    
        if ((err = at_parser_max_params_from_str(buf, NULL, &resp_list,
                                                 AT_CESQ_PARAMS_COUNT_MAX)))
        {
            printk("Could not parse AT+CESQ response, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
    
        /* Check if AT command response starts with +CESQ */
        if ((err = at_params_string_get(&resp_list, AT_CESQ_RESPONSE_PREFIX_INDEX,
                                        response_prefix, &response_prefix_len)))
        {
            printk("Could not get response prefix, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
    
        if (strncmp(response_prefix, AT_CESQ_RESPONSE_PREFIX, response_prefix_len))
        {
            /* The unsolicited response is not a CESQ response, ignore it.
             */
            printk("String not matching %s\n", response_prefix);
            at_params_list_free(&resp_list);
            return err;
        }
    
        if ((err =
                 at_params_int_get(&resp_list, AT_CESQ_RESPONSE_RSRQ_INDEX, &value)) != 0)
        {
            printk("Could not get RSRQ: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
        *rsrq = (s16_t)value;
    
        if ((err =
                 at_params_int_get(&resp_list, AT_CESQ_RESPONSE_RSRP_INDEX, &value)) != 0)
        {
            printk("Could not get RSRP, error: %d\n", err);
            at_params_list_free(&resp_list);
            return err;
        }
        *rsrp = (s16_t)value;
    
        at_params_list_free(&resp_list);
        return err;
    }
    
    /*=============================================================================*/
    
    int device_getDevID()
    {
        int err;
        enum at_cmd_state at_state;
        char imei_buf[IMEI_LEN + 5];
    
        if ((err = at_cmd_write("AT+CGSN", imei_buf, IMEI_LEN + 5, &at_state)))
        {
            printk("Error when trying to do at_cmd_write: %d, at_state: %d", err,
                   at_state);
            return err;
        }
    
        snprintf(dev_id, 20, "nrf-%s", imei_buf);
        return err;
    }
    
    /*=============================================================================*/
    
    /**
     * @brief Handle events sent from AWS MQTT server
     *
     * @param evt
     */
    void aws_iot_evt_handler(const struct aws_iot_evt *evt)
    {
        printk("aws_iot_evt_handler %d\r\n", evt->type);
    
        if (evt->type == AWS_IOT_EVT_READY)
        {
            connected = true;
            led_switchOff();
        }
    }
    
    /*=============================================================================*/
    
    int aws_init(void)
    {
        int err;
    
        device_getDevID();
        config.client_id     = dev_id;
        config.client_id_len = strlen(dev_id);
    
        if ((err = aws_iot_init(&config, aws_iot_evt_handler)) == 0)
        {
            printk("aws_iot_initialized\r\n");
        }
        else
        {
            printk("aws_iot_init failed: %d\n", err);
            return err;
        }
        return err;
    }
    
    /*=============================================================================*/
    
    void aws_connect(void)
    {
        int err;
        while ((err = aws_iot_connect(&config)) != 0)
        {
            printk("aws_iot_connect failed: %d\n", err);
            k_sleep(5000);
        }
    
        printk("aws_iot_connected\n");
        return;
    }
    
    /*=============================================================================*/
    
    void aws_reconnect(void)
    {
        int err;
        
        aws_iot_disconnect();
        aws_init();
        connected = false;
        led_switchOn();
        aws_connect();
        
        return;
    }
    
    /*=============================================================================*/
    
    /**
     * @brief
     *
     * @return int
     */
    static int aws_publish_data()
    {
        int err                     = 0;
        static uint32_t msg_counter = 0;
        float temperature           = 0;
        u16_t battery_voltage       = 0;
        s16_t rsrp                  = 0;
        s16_t rsrq                  = 0;
    
        tempSensor_getTemperature(&temperature);
        tempSensor_getBatteryVoltage(&battery_voltage);
        modem_getSignalStrength(&rsrp, &rsrq);
    
        /* Send data to topic */
        char topic_msg[256];
        sprintf(topic_msg,
                "{\"state\":{\"reported\":{\"device\":\"%s\", "
                "\"message_count\":\"%d\", "
                "\"temperature\":\"%.2f\", \"battery_level\":\"%d\", "
                "\"RSRQ\":\"%d\", \"RSRP\":\"%d\"}}}",
                dev_id, ++msg_counter, temperature, battery_voltage, rsrq, rsrp);
    
        char *topic_name = "concr/temperature";
    
        struct aws_iot_topic_data topic = {
            /** Type of shadow topic that will be published to. */
            // enum aws_iot_topic_type
            .type = AWS_IOT_SHADOW_TOPIC_UPDATE,
            /** Pointer to string of application specific topic. */
            // char *
            .str = topic_name,
            /** Length of application specific topic. */
            // size_t
            .len = strlen(topic_name),
        };
    
        const struct aws_iot_tx_data tx_data = {
            /** Topic that the message will be sent to. */
            // struct aws_iot_topic_data
            .topic = topic,
            /** Pointer to message to be sent to AWS IoT broker. */
            .str = topic_msg,
            /** Length of message. */
            .len = strlen(topic_msg),
            /** Quality of Service of the message. */
            .qos = 1,
        };
    
        if (aws_iot_send(&tx_data) != 0)
        {
            printk("Failed to publish sensor data\r\n");
        }
        else
        {
            printk("Publish Sensor Data\r\n");
            printk("DATA: %s\r\n", topic_msg);
        }
    
        return err;
    }
    
    /*=============================================================================*/
    
    void fds_init(void)
    {
        fds.fd     = config.socket;
        fds.events = POLLIN;
    }
    
    /*=============================================================================*/
    
    int led_init(void)
    {
        int err;
        gpio_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    
        if (!gpio_dev)
        {
            printk("Error getting " DT_GPIO_P0_DEV_NAME " device binding\r\n");
            err = 1;
            return err;
        }
    
        gpio_pin_configure(gpio_dev, RED_LED, GPIO_DIR_OUT);
        return err;
    }
    
    /*=============================================================================*/
    
    void led_switchOn(void) { gpio_pin_write(gpio_dev, RED_LED, LED_ON); }
    
    /*=============================================================================*/
    
    void led_switchOff(void) { gpio_pin_write(gpio_dev, RED_LED, LED_OFF); }
    
    
    /*=============================================================================*/
    
    /**
     * @brief
     *
     */
    void main(void)
    {
        printk("NRF9160 Temperature Sensor Started...!!!\r\n");
        int err;
    
        s64_t time_stamp     = k_uptime_get();
        s32_t delay_interval = K_SECONDS(DEVICE_SLEEP_INTERVAL);
        s32_t awake_interval = K_SECONDS(DEVICE_AWAKE_INTERVAL);
    
        led_init();
        led_switchOn();
        modem_configure();
        modem_setup_psm();
        tempSensor_init();
        aws_init();
        aws_connect();
        fds_init();
    
        printk("Initialized successfully in %lldms\n", k_uptime_delta(&time_stamp));
    
        while (true)
        {
            printk("\n");
    
            if(connected == false)
            {
                //Wait to be connected before publishing data
                delay_interval = 0;
                awake_interval = K_SECONDS(CONFIG_MQTT_KEEPALIVE);
            }
            else
            {
                //After connection publish data to thje AWS server
                delay_interval = K_SECONDS(DEVICE_SLEEP_INTERVAL);
                awake_interval = K_SECONDS(DEVICE_AWAKE_INTERVAL);
                aws_publish_data();
            }
            
            err = poll(&fds, 1, awake_interval);
    
            if (err < 0)
            {
                printk("poll() returned an error: %d\n", err);
                continue;
            }
            else if (err == 0)
            {
                if(aws_iot_keepalive_time_left() < 0)
                {
                    aws_iot_ping();
                    continue;
                }
            }        
    
            if ((fds.revents & POLLIN) == POLLIN)
            {
                aws_iot_input();
            }
    
            if ((fds.revents & POLLNVAL) == POLLNVAL)
            {
                printk("Socket error: POLLNVAL\n");
                printk("The AWS IoT socket was unexpectedly closed.\n");
                aws_reconnect();
                continue;
            }
    
            if ((fds.revents & POLLHUP) == POLLHUP)
            {
                printk("Socket error: POLLHUP\n");
                printk("Connection was closed by the AWS IoT broker.\n");
                aws_reconnect();
                continue;
            }
    
            if ((fds.revents & POLLERR) == POLLERR)
            {
                printk("Socket error: POLLERR\n");
                printk("AWS IoT broker connection was unexpectedly closed.\n");
                aws_reconnect();
                continue;
            }
    
            k_sleep(delay_interval);
        }   
    }
    /*=============================================================================
     *                             Public Functions
     *==============================================================================*/
    
    /*=============================================================================
     *                             End of File
     *==============================================================================*/
    

Children
No Data
Related