Hi,
I haven't ran the FOTA download library in a while and I was just testing it. I don't seem to be getting any of the FOTA_DOWNLOAD_EVT events. I am running nRF SDK v1.2.1. I also have the LWM2M carrier library running, not sure if that affects this at all.
Normally I use the success event (FOTA_DOWNLOAD_EVT_FINISHED) to trigger a system reboot. However, this event is not firing and thus I can't trigger the reboot.
I also just ran and got a failure because it couldn't open a socket. Which I normally handle by reporting to another connected device that the update has failed, however, that event also isn't firing.
I have attached my source code that uses the fota_download library.
Here are the logs during an error:
[00:00:11.617,065] <inf> download_client: Attempting to connect over IPv4
[00:00:11.761,932] <inf> download_client: Connected to <hidden>
[00:00:11.771,331] <inf> download_client: Downloading: modem-fw/mfw_nrf9160_update_from_1.1.1_to_1.1.2.bin [0]
[00:00:12.075,683] <wrn> download_client: Copying 280 payload bytes
[00:00:13.077,453] <inf> download_client: Downloaded 4096/14822 bytes (27%)
[00:00:13.085,174] <err> dfu_target_modem: Failed to open Modem DFU socket.
[00:00:13.093,078] <err> fota_download: dfu_target_init error -1
[00:00:13.100,036] <inf> download_client: Fragment refused, download stopped.
Does the LWM2M carrier library running cause any issues with the fota_download library? I did get a successful update but for some reason the events didn't fire.
Thanks,
Jack
/*
modem_upgrade.c
Implement Modem FW Upgrade
*/
#include <zephyr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/fota_download.h>
#include <modem_info.h>
#include <dfu/mcuboot.h>
#include <hal/nrf_regulators.h>
#include "modem_upgrade.h"
#include "cloud.h"
#include "uart_comm.h"
#include "cmd.h"
// Variables ==========================================================
static struct k_delayed_work fota_work;
static struct download_client dlc;
static char fw_host[HTTP_HEADER_SIZE];
static char fw_file[HTTP_HEADER_SIZE];
// Internal Function Prototypes ======================================
static void fota_dl_handler(enum fota_download_evt_id evt_id);
static void modem_fota_work(struct k_work *unused);
static int check_for_fw_update(char* apiHost, char* apiVersion);
static void parse_fota_response(char* fotaResponse, int* upgradeAvailable, char* fwHost, char* fwFile, char* responseCode);
static void parse_http_header(char *input, char *key, char *value);
// Public Functions ==================================================
int MODEM_UPGRADE_init(void)
{
printf("Initializing modem FOTA\n");
k_work_init(&fota_work, modem_fota_work);
int err = fota_download_init(fota_dl_handler);
if (err != 0) {
printf("Error initializing fota download: %d\n", err);
}
err = modem_info_init();
if (err != 0) {
printf("Error initializing modem info: %d\n", err);
}
printf("Modem FOTA Initialized\n");
return 0;
}
int MODEM_UPGRADE_check_for_upgrade(char* dcdApiHost, char* apiVersion)
{
int response = check_for_fw_update(dcdApiHost, apiVersion);
if (response == 1)
{
printf("Modem FW Upgrade available...\n");
return 1;
}
else if (response == 0)
{
printf("No Modem FW Upgrade available...\n");
CLOUD_lteOff();
return 0;
}
else
{
CLOUD_lteOff();
return -1;
}
}
int MODEM_UPGRADE_do_upgrade(void)
{
printf("Running modem FOTA\n");
k_work_submit(&fota_work);
return 0;
}
int MODEM_UPGRADE_get_version(char* modemVersion)
{
char buffer[MODEM_VERSION_MAX_LENGTH];
int length = modem_info_string_get(MODEM_INFO_FW_VERSION, buffer);
memcpy(modemVersion, buffer, length);
modemVersion[length] = '\0';
return 0;
}
// Private Functions ===================================================
static void fota_dl_handler(enum fota_download_evt_id evt_id)
{
switch (evt_id) {
case FOTA_DOWNLOAD_EVT_ERROR:
printf("Received error from fota_download\n");
UART_sendMessage(MSG_CMD_MODEM_FOTA_FAILED, NULL, 0);
break;
case FOTA_DOWNLOAD_EVT_FINISHED:
printf("FOTA download complete. rebooting...\n");
sys_reboot(0);
break;
default:
break;
}
}
static void modem_fota_work(struct k_work *unused)
{
int retval;
retval = fota_download_start(fw_host, fw_file);
if (retval != 0) {
printf("fota_download_start() failed, err %d\n", retval);
}
}
static int check_for_fw_update(char* apiHost, char* apiVersion)
{
char fwVersion[MODEM_VERSION_MAX_LENGTH];
MODEM_UPGRADE_get_version(fwVersion);
char request_buffer[HTTP_BUFF_SIZE];
char response_buffer[HTTP_BUFF_SIZE];
char response_code[4];
int usedSize = sprintf(request_buffer, "GET /api/%s/modem/fota HTTP/1.1\r\n"
"Host: %s\r\n"
"modem-fw-version: %s\r\n"
"Connection: close\r\n\r\n", apiVersion, apiHost, fwVersion);
CLOUD_lteConnect();
CLOUD_sendHttpRequest(apiHost, request_buffer, response_buffer, HTTP_BUFF_SIZE);
int upgradeAvailable = 0;
parse_fota_response(response_buffer, &upgradeAvailable, fw_host, fw_file, response_code);
if (strcmp(response_code, "200")) {
printf("Check for modem FOTA request failed: HTTP %s\n", response_code);
return -1;
}
return upgradeAvailable;
}
char *strtok(char * str, const char * delim)
{
static char* p=0;
if(str)
p=str;
else if(!p)
return 0;
str=p+strspn(p,delim);
p=str+strcspn(str,delim);
if(p==str)
return p=0;
p = *p ? *p=0,p+1 : 0;
return str;
}
static void parse_fota_response(char* fotaResponse, int* upgradeAvailable, char* fwHost, char* fwFile, char* responseCode)
{
char headerKey[HTTP_HEADER_SIZE];
char headerValue[HTTP_HEADER_SIZE];
char *token = NULL;
token = strtok(fotaResponse, "\r\n");
while(token) {
parse_http_header(token, headerKey, headerValue);
if (!strcmp(headerKey, "upgrade-available"))
{
u8_t b = headerValue[0];
b = b - '0';
*upgradeAvailable = b;
}
if (!strcmp(headerKey, "fw-host"))
{
strcpy(fwHost, headerValue);
}
if (!strcmp(headerKey, "fw-file"))
{
strcpy(fwFile, headerValue);
}
if (strstr(headerKey, "HTTP/1.1"))
{
strncpy(responseCode, headerKey + 9, 3);
responseCode[3] = '\0';
}
token = strtok(NULL, "\r\n");
if (token == " ") { token = NULL; }
}
}
static void parse_http_header(char *input, char *key, char *value)
{
int colonReached = 0;
int j = 0;
int i = 0;
for (i = 0; i < strlen(input); i++)
{
if (input[i] == ':')
{
colonReached = 1;
key[i] = '\0';
i += 2; // skip the colon and the space seperating key: value
}
if (colonReached)
{
// start parsing the value with new index at 0
value[j] = input[i];
j++;
}
else
{
// parse the key until we hit a colon & space ': '
key[i] = input[i];
}
}
// If we don't hit a colon, then just add a null terminator on the key
if (!colonReached) { key[i] = '\0'; }
value[j] = '\0';
}