Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to update modules #43

Merged
merged 6 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ Additionally, building the Device Troubleshoot add-on requires [msgpack-c](https

The examples provide details to generate properly the artifact to be used. The most important is to create artifact with no compression at all, because the mender-mcu-client is not able to manage decompression of the artifact on the fly (it is flashed by blocks during the reception from the mender server).

To create a new artifact first retrieve [mender-artifact](https://docs.mender.io/downloads#mender-artifact) tool. Then you should follow the template below to create the artifact:
Artifact are created using [mender-artifact](https://docs.mender.io/downloads#mender-artifact) tool.

### rootfs-image

Follow the template below to create an artifact intended for firmware update:

```
./mender-artifact write rootfs-image --compression none --device-type <DEVICE-TYPE> --artifact-name <ARTIFACT-NAME> --output-path <ARTIFACT-FILE>.mender --file <BIN-FILE>
Expand All @@ -66,6 +70,21 @@ Where:
* `ARTIFACT-FILE` is the artifact output file to be uploaded on mender server.
* `BIN-FILE` is the application binary file to be flashed on the MCU in the next OTA partition.

### module-image

Follow the template below to create an artifact intended for module update:

```
./mender-artifact write module-image --compression none --device-type <DEVICE-TYPE> --artifact-name <ARTIFACT-NAME> --type <MODULE-TYPE> --output-path <ARTIFACT-FILE>.mender --file <MODULE-FILE>
```

Where:
* `DEVICE-TYPE` is the device type to be used on mender, for example `my-super-device`.
* `ARTIFACT-NAME` is the artifact name to be used on mender, it should include the version number, for example `my-artifact-v1.0.0`.
* `MODULE-TYPE` is the module type to be registered on the device to the mender client, for example `my-artifact`.
* `ARTIFACT-FILE` is the artifact output file to be uploaded on mender server.
* `MODULE-FILE` is the module file to be upgraded on the MCU. Multiple files are allowed repeating the option.


## API

Expand Down Expand Up @@ -143,7 +162,6 @@ It is possible to reduce even more the footprint of the mender-mcu-client librar

The following features are currently in the pipeline. Please note that I haven't set dates in this road-map because I develop this in my free time, but you can contribute with Pull Requests:

* Support update of [modules](https://docs.mender.io/artifact-creation/create-a-custom-update-module) to perform other kind of updates that could be specific to one project: files, images, etc.
* Integration of other nice to have Mender features: Device Troubleshoot sending and receiving files, ...
* Support new boards and prove it is cross-platform and that it is able to work on small MCU too: STM32F7, ATSAMD51...
* Support other RTOS (particularly Azure RTOS) and bare metal platforms.
Expand Down
155 changes: 140 additions & 15 deletions add-ons/src/mender-configure.c
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/

#include "mender-api.h"
#include "mender-client.h"
#include "mender-configure.h"
#include "mender-log.h"
#include "mender-rtos.h"
Expand Down Expand Up @@ -67,10 +68,28 @@ static void *mender_configure_work_handle = NULL;
*/
static mender_err_t mender_configure_work_function(void);

/**
* @brief Callback function to be invoked to perform the treatment of the data from the artifact type "mender-configure"
* @param id ID of the deployment
* @param artifact name Artifact name
* @param type Type from header-info payloads
* @param meta_data Meta-data from header tarball
* @param filename Artifact filename
* @param size Artifact file size
* @param data Artifact data
* @param index Artifact data index
* @param length Artifact data length
* @return MENDER_OK if the function succeeds, error code if an error occured
*/
static mender_err_t mender_configure_download_artifact_callback(
char *id, char *artifact_name, char *type, cJSON *meta_data, char *filename, size_t size, void *data, size_t index, size_t length);

mender_err_t
mender_configure_init(mender_configure_config_t *config, mender_configure_callbacks_t *callbacks) {

assert(NULL != config);
char * device_config = NULL;
cJSON * json_device_config = NULL;
mender_err_t ret;

/* Save configuration */
Expand All @@ -86,28 +105,40 @@ mender_configure_init(mender_configure_config_t *config, mender_configure_callba
/* Create configure mutex */
if (MENDER_OK != (ret = mender_rtos_mutex_create(&mender_configure_mutex))) {
mender_log_error("Unable to create configure mutex");
return ret;
goto END;
}

#ifdef CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE

/* Initialize configuration from storage (if it is not empty) */
char *device_config = NULL;
if (MENDER_OK != (ret = mender_storage_get_device_config(&device_config))) {
if (MENDER_NOT_FOUND != ret) {
mender_log_error("Unable to get device configuration");
return ret;
goto END;
}
}

/* Set device configuration */
if (NULL != device_config) {
if (MENDER_OK != (ret = mender_utils_keystore_from_string(&mender_configure_keystore, device_config))) {
if (NULL == (json_device_config = cJSON_Parse(device_config))) {
mender_log_error("Unable to set device configuration");
free(device_config);
return ret;
ret = MENDER_FAIL;
goto END;
}
if (MENDER_OK != (ret = mender_utils_keystore_from_json(&mender_configure_keystore, cJSON_GetObjectItemCaseSensitive(json_device_config, "config")))) {
mender_log_error("Unable to set device configuration");
goto END;
}
free(device_config);
}

/* Register mender-configure artifact type */
if (MENDER_OK
!= (ret = mender_client_register_artifact_type("mender-configure",
&mender_configure_download_artifact_callback,
true,
cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(json_device_config, "artifact_name"))))) {
mender_log_error("Unable to register 'mender-configure' artifact type");
goto END;
}

#endif /* CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE */
Expand All @@ -119,7 +150,17 @@ mender_configure_init(mender_configure_config_t *config, mender_configure_callba
configure_work_params.name = "mender_configure";
if (MENDER_OK != (ret = mender_rtos_work_create(&configure_work_params, &mender_configure_work_handle))) {
mender_log_error("Unable to create configure work");
return ret;
goto END;
}

END:

/* Release memory */
if (NULL != device_config) {
free(device_config);
}
if (NULL != json_device_config) {
cJSON_Delete(json_device_config);
}

return ret;
Expand Down Expand Up @@ -168,6 +209,9 @@ mender_configure_get(mender_keystore_t **configuration) {
mender_err_t
mender_configure_set(mender_keystore_t *configuration) {

cJSON * json_device_config = NULL;
cJSON * json_config = NULL;
char * device_config = NULL;
mender_err_t ret;

/* Take mutex used to protect access to the configuration key-store */
Expand All @@ -191,22 +235,43 @@ mender_configure_set(mender_keystore_t *configuration) {
#ifdef CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE

/* Save the device configuration */
char *device_config = NULL;
if (MENDER_OK != (ret = mender_utils_keystore_to_string(mender_configure_keystore, &device_config))) {
if (NULL == (json_device_config = cJSON_CreateObject())) {
mender_log_error("Unable to allocate memory");
ret = MENDER_FAIL;
goto END;
}
if (MENDER_OK != (ret = mender_utils_keystore_to_json(mender_configure_keystore, &json_config))) {
mender_log_error("Unable to format configuration");
goto END;
}
if (NULL != device_config) {
if (MENDER_OK != (ret = mender_storage_set_device_config(device_config))) {
mender_log_error("Unable to record configuration");
}
free(device_config);
if (NULL == json_config) {
mender_log_error("Unable to format configuration");
ret = MENDER_FAIL;
goto END;
}
cJSON_AddItemToObject(json_device_config, "config", json_config);
if (NULL == (device_config = cJSON_PrintUnformatted(json_device_config))) {
mender_log_error("Unable to allocate memory");
ret = MENDER_FAIL;
goto END;
}
if (MENDER_OK != (ret = mender_storage_set_device_config(device_config))) {
mender_log_error("Unable to record configuration");
goto END;
}

#endif /* CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE */

END:

/* Release memory */
if (NULL != json_device_config) {
cJSON_Delete(json_device_config);
}
if (NULL != device_config) {
free(device_config);
}

/* Release mutex used to protect access to the configuration key-store */
mender_rtos_mutex_give(mender_configure_mutex);

Expand Down Expand Up @@ -314,4 +379,64 @@ mender_configure_work_function(void) {
return ret;
}

#ifdef CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE

static mender_err_t
mender_configure_download_artifact_callback(
char *id, char *artifact_name, char *type, cJSON *meta_data, char *filename, size_t size, void *data, size_t index, size_t length) {

(void)id;
(void)type;
(void)filename;
(void)size;
(void)data;
(void)index;
(void)length;
cJSON * json_device_config = NULL;
char * device_config = NULL;
mender_err_t ret = MENDER_OK;

/* Check meta-data */
if (NULL != meta_data) {

/* Save the device configuration */
if (NULL == (json_device_config = cJSON_CreateObject())) {
mender_log_error("Unable to allocate memory");
ret = MENDER_FAIL;
goto END;
}
cJSON_AddStringToObject(json_device_config, "artifact_name", artifact_name);
cJSON_AddItemToObject(json_device_config, "config", meta_data);
if (NULL == (device_config = cJSON_PrintUnformatted(json_device_config))) {
mender_log_error("Unable to allocate memory");
ret = MENDER_FAIL;
goto END;
}
if (MENDER_OK != (ret = mender_storage_set_device_config(device_config))) {
mender_log_error("Unable to record configuration");
goto END;
}

} else {

/* Delete the configuration */
if (MENDER_OK != (ret = mender_storage_delete_device_config())) {
mender_log_error("Unable to delete configuration");
}
}

END:

/* Release memory */
if (NULL != json_device_config) {
cJSON_Delete(json_device_config);
}
if (NULL != device_config) {
free(device_config);
}
return ret;
}

#endif /* CONFIG_MENDER_CLIENT_CONFIGURE_STORAGE */

#endif /* CONFIG_MENDER_CLIENT_ADD_ON_CONFIGURE */
26 changes: 21 additions & 5 deletions core/src/mender-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,17 @@ mender_api_download_configuration_data(mender_keystore_t **configuration) {

/* Treatment depending of the status */
if (200 == status) {
if (MENDER_OK != (ret = mender_utils_keystore_from_string(configuration, response))) {
cJSON *json_response = cJSON_Parse(response);
if (NULL == json_response) {
mender_log_error("Unable to set configuration");
goto END;
}
if (MENDER_OK != (ret = mender_utils_keystore_from_json(configuration, json_response))) {
mender_log_error("Unable to set configuration");
cJSON_Delete(json_response);
goto END;
}
cJSON_Delete(json_response);
} else {
mender_api_print_response_error(response, status);
ret = MENDER_FAIL;
Expand All @@ -469,15 +476,21 @@ mender_err_t
mender_api_publish_configuration_data(mender_keystore_t *configuration) {

mender_err_t ret;
char * payload = NULL;
char * response = NULL;
int status = 0;
cJSON * json_configuration = NULL;
char * payload = NULL;
char * response = NULL;
int status = 0;

/* Format payload */
if (MENDER_OK != (ret = mender_utils_keystore_to_string(configuration, &payload))) {
if (MENDER_OK != (ret = mender_utils_keystore_to_json(configuration, &json_configuration))) {
mender_log_error("Unable to format payload");
goto END;
}
if (NULL == (payload = cJSON_PrintUnformatted(json_configuration))) {
mender_log_error("Unable to allocate memory");
ret = MENDER_FAIL;
goto END;
}

/* Perform HTTP request */
if (MENDER_OK
Expand Down Expand Up @@ -511,6 +524,9 @@ mender_api_publish_configuration_data(mender_keystore_t *configuration) {
if (NULL != payload) {
free(payload);
}
if (NULL != json_configuration) {
cJSON_Delete(json_configuration);
}

return ret;
}
Expand Down
Loading
Loading