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

nRF9160: AWS IoT Sample Application

Hi,

I am trying to run the nRF9160 AWS IoT sample - https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/nrf9160/aws_iot/README.html on an nRF9160 DK, but have had no luck. I have done all setup, but the code fails during AWS IoT initialisation:

*** Booting Zephyr OS build v2.4.0-ncs1  ***
The AWS IoT sample started, version: v1.0.0
E: aws_topics_populate, error: -12
AWS IoT library could not be initialized, error: -12

I have inspected the call stack, and noticed that aws_topics_populate is called by aws_iot_init, which in turn is called from main.c as follows:

err = aws_iot_init(NULL, aws_iot_event_handler);
if (err) {
	printk("AWS IoT library could not be initialized, error: %d\n", err);
}

From the above, the first argument to the function is NULL, is this expected? I noticed that this maps to the aws_iot_config * parameter inside the function declaration in aws_iot.c, and the argument actually gets used, with failure eventually happening inside aws_topics_populate

I read the AWS IoT library documentation - https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/include/net/aws_iot.html#lib-aws-iot, and encountered the note:

The API requires that a configuration structure aws_iot_config is declared in the application and passed into the aws_iot_init() and aws_iot_connect() functions. This exposes the application to the MQTT socket used for the connection, which is polled on, in the application. It also enables the application to pass in a client id (thingname) at runtime.

I then set out to create an instance of the struct, but couldn't figure out what the socket field should be set to. 

Question: Am I on the right path the and aws_iot_config instance needs to be created for the nRF9160 AWS IoT sample even though the sample documentation doesn't say so explicitly. And if so, how do determine what the socket value should be set to?

The API requires that a configuration structure aws_iot_config is declared 
in the application and passed into the aws_iot_init() and aws_iot_connect() 
functions. This exposes the application to the MQTT socket used for the 
connection, which is polled on, in the application. It also enables the 
application to pass in a client id (thingname) at runtime.

  • Hi,

    The sample seems to be working for me. I still get an error (when I call getaddrinfo, it does not find the hostname), but that is probably just an error on my end. Anyway, the error I get comes after the point where I should have seen your error, so the call to aws_iot_init returns successfully.

    Looking at the code, the argument is not used in aws_topics_populate, unless you have set CONFIG_AWS_IOT_CLIENT_ID_APP. Do you know which call to snprintf fails in aws_topics_populate.

    As for the note, I think that it is only for when CONFIG_IOT_CLIENT_ID_APP is set. But I agree that the note is confusing, and I will talk to our developers to see if it can be improved.

    The socket will be created and set when you call aws_iot_connect, so you do not need to set that field yourself.

    Best regards,

    Didrik

  • Hi Didrik,

    Thanks for picking this up, and kindly getting back to me.

    I can confirm that CONFIG_AWS_IOT_CLIENT_ID_APP is not set.

    The aws_iot_init implementation is as follows:

    int aws_iot_init(const struct aws_iot_config *const config,
    		 aws_iot_evt_handler_t event_handler)
    {
    	int err;
    
    	if (IS_ENABLED(CONFIG_AWS_IOT_CLIENT_ID_APP) &&
    	    config->client_id_len >= CONFIG_AWS_IOT_CLIENT_ID_MAX_LEN) {
    		LOG_ERR("Client ID string too long");
    		return -EMSGSIZE;
    	}
    
    	if (IS_ENABLED(CONFIG_AWS_IOT_CLIENT_ID_APP) &&
    	    config->client_id == NULL) {
    		LOG_ERR("Client ID not set in the application");
    		return -ENODATA;
    	}
    
    	err = aws_iot_topics_populate(config->client_id, config->client_id_len);
    	if (err) {
    		LOG_ERR("aws_topics_populate, error: %d", err);
    		return err;
    	}
    
    #if defined(CONFIG_AWS_FOTA)
    	err = aws_fota_init(&client, aws_fota_cb_handler);
    	if (err) {
    		LOG_ERR("aws_fota_init, error: %d", err);
    		return err;
    	}
    #endif
    
    	module_evt_handler = event_handler;
    
    	return err;
    }

    so if a NULL argument is passed for aws_iot_config*, config->client_id evaluates to garbage I would assume but as you correctly stated is not used inside aws_iot_topics_populate. 

    I tried debugging into aws_iot_topics_populate to see where the failure is happening but for some reason the debugger won't step into the C function. Here's a screenshot of what I get:

    I thought the reason may be due to optimisations done by the compiler, so I tried the below setting in prj.conf:

    CONFIG_DEBUG_OPTIMIZATIONS=y

    but still couldn't step into the function. In fact, the code seems to crash... please see below:

    Any suggestions / pointers?

  • Quick update, it appears my client-id is long, so had to adjust CONFIG_AWS_IOT_CLIENT_ID_MAX_LEN. I am no longer getting the error. However, I am yet to make sense why I was unable to step into the aws_topics_populate function. Would you be able to advise.

  • Hi, and sorry for the late response.

    It's good to hear that you found the cause of the error.

    I haven't been able to look much into why you are not able to step into the aws_topics_populate function, but I will do so early next week.

    Best regards,

    Didrik

  • I can confirm that I see the crash when calling aws_topics_populate both with no optimizations and with debug optimizations. The call does not crash when optimizing for size or speed.

    I haven't yet found a good reason for why the crash happens, but I have informed the developers of that library.

    To me, it seems like aws_topics_populate is inlined in aws_iot_init when optimizing for speed or size. You can still step through the function, but it will look like you are inside the aws_iot_init function. This is exacerbated by the fact that aws_topics_populate is almost exclusively calls to snprintf, so most time would be spent there, rather than the few assembly instructions that "actually" come from aws_topics_populate.

    I can agree that it is not be best debugging experience, but other than the crash when not optimizing the code, I can not find anything wrong.

Related