net: lwm2m: add firmware push support
1. Add handling block1 option in handle_request(). The basic idea is to declare structure block_context at compiled time and use "token" as a key to pick up the on-going block cotext. It should be able to support multiple blockwise transfer concurrently 2. Use write callback implemented in lwm2m_obj_firmware to deal w/ the update state transition and than call the callback registered by the application 3. move default_block_size to lwm2m_engine.c to share between lwm2m_engine and lwm2m_obj_firmware_pull Signed-off-by: Robert Chou <robert.ch.chou@acer.com> [michael.scott@linaro.org: rebased on LwM2M net_app changes.] Signed-off-by: Michael Scott <michael.scott@linaro.org>
This commit is contained in:
parent
f6188fbce3
commit
b93eb8dee1
7 changed files with 292 additions and 84 deletions
|
@ -123,10 +123,10 @@ int lwm2m_device_add_err(u8_t error_code);
|
|||
#define RESULT_UNSUP_PROTO 9
|
||||
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
|
||||
void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb);
|
||||
lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void);
|
||||
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
|
||||
void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb);
|
||||
lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void);
|
||||
#endif
|
||||
|
|
|
@ -147,6 +147,7 @@ static int device_factory_default_cb(u16_t obj_inst_id)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
|
||||
static int firmware_update_cb(u16_t obj_inst_id)
|
||||
{
|
||||
SYS_LOG_DBG("UPDATE");
|
||||
|
@ -160,7 +161,9 @@ static int firmware_update_cb(u16_t obj_inst_id)
|
|||
lwm2m_engine_set_u8("5/0/5", RESULT_SUCCESS);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
|
||||
static int firmware_block_received_cb(u16_t obj_inst_id,
|
||||
u8_t *data, u16_t data_len,
|
||||
bool last_block, size_t total_size)
|
||||
|
@ -169,6 +172,7 @@ static int firmware_block_received_cb(u16_t obj_inst_id,
|
|||
data_len, last_block);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lwm2m_setup(void)
|
||||
{
|
||||
|
@ -212,10 +216,12 @@ static int lwm2m_setup(void)
|
|||
|
||||
/* setup FIRMWARE object */
|
||||
|
||||
lwm2m_engine_register_post_write_callback("5/0/0",
|
||||
firmware_block_received_cb);
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
|
||||
lwm2m_firmware_set_write_cb(firmware_block_received_cb);
|
||||
#endif
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT)
|
||||
lwm2m_firmware_set_update_cb(firmware_update_cb);
|
||||
#endif
|
||||
|
||||
/* setup TEMP SENSOR object */
|
||||
|
||||
|
|
|
@ -137,17 +137,23 @@ config LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
|
|||
block transfer and "FIRMWARE PACKAGE URI" resource. This option
|
||||
adds another UDP context and packet handling.
|
||||
|
||||
config LWM2M_FIRMWARE_UPDATE_PULL_COAP_BLOCK_SIZE
|
||||
int "Firmware Update object pull CoAP block size"
|
||||
depends on LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT
|
||||
config LWM2M_COAP_BLOCK_SIZE
|
||||
int "LWM2M CoAP block-wise transfer size"
|
||||
default 256
|
||||
default 64 if NET_L2_BT
|
||||
default 64 if NET_L2_IEEE802154
|
||||
range 16 1024
|
||||
help
|
||||
CoAP block size used by firmware pull when performing block-wise
|
||||
CoAP block size used by LWM2M when performing block-wise
|
||||
transfers. Possible values: 16, 32, 64, 128, 256, 512 and 1024.
|
||||
|
||||
config LWM2M_NUM_BLOCK1_CONTEXT
|
||||
int "Maximum # of LWM2M block1 contexts"
|
||||
default 3
|
||||
help
|
||||
This value sets up the maximum number of block1 contexts for
|
||||
CoAP block-wise transfer we can handle at the same time.
|
||||
|
||||
config LWM2M_RW_JSON_SUPPORT
|
||||
bool "support for JSON writer"
|
||||
default y
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
*
|
||||
* - Use server / security object instance 0 for initial connection
|
||||
* - Add DNS support for security uri parsing
|
||||
* - Block-transfer support / Large response messages
|
||||
* (use Block2 to limit message size to 64 bytes for 6LOWPAN compat.)
|
||||
* - BOOTSTRAP/DTLS cleanup
|
||||
* - Handle WRITE_ATTRIBUTES (pmin=10&pmax=60)
|
||||
* - Handle Resource ObjLink type
|
||||
|
@ -102,6 +100,24 @@ static sys_slist_t engine_obj_list;
|
|||
static sys_slist_t engine_obj_inst_list;
|
||||
static sys_slist_t engine_observer_list;
|
||||
|
||||
#define NUM_BLOCK1_CONTEXT CONFIG_LWM2M_NUM_BLOCK1_CONTEXT
|
||||
|
||||
/* TODO: figure out what's correct value */
|
||||
#define TIMEOUT_BLOCKWISE_TRANSFER K_SECONDS(30)
|
||||
|
||||
#define GET_BLOCK_NUM(v) ((v) >> 4)
|
||||
#define GET_BLOCK_SIZE(v) (((v) & 0x7))
|
||||
#define GET_MORE(v) (!!((v) & 0x08))
|
||||
|
||||
struct block_context {
|
||||
struct zoap_block_context ctx;
|
||||
s64_t timestamp;
|
||||
u8_t token[8];
|
||||
u8_t tkl;
|
||||
};
|
||||
|
||||
static struct block_context block1_contexts[NUM_BLOCK1_CONTEXT];
|
||||
|
||||
/* periodic / notify / observe handling stack */
|
||||
static K_THREAD_STACK_DEFINE(engine_thread_stack,
|
||||
CONFIG_LWM2M_ENGINE_STACK_SIZE);
|
||||
|
@ -160,6 +176,101 @@ static char *sprint_token(const u8_t *token, u8_t tkl)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* block-wise transfer functions */
|
||||
|
||||
enum zoap_block_size lwm2m_default_block_size(void)
|
||||
{
|
||||
switch (CONFIG_LWM2M_COAP_BLOCK_SIZE) {
|
||||
case 16:
|
||||
return ZOAP_BLOCK_16;
|
||||
case 32:
|
||||
return ZOAP_BLOCK_32;
|
||||
case 64:
|
||||
return ZOAP_BLOCK_64;
|
||||
case 128:
|
||||
return ZOAP_BLOCK_128;
|
||||
case 256:
|
||||
return ZOAP_BLOCK_256;
|
||||
case 512:
|
||||
return ZOAP_BLOCK_512;
|
||||
case 1024:
|
||||
return ZOAP_BLOCK_1024;
|
||||
}
|
||||
|
||||
return ZOAP_BLOCK_256;
|
||||
}
|
||||
|
||||
static int
|
||||
init_block_ctx(const u8_t *token, u8_t tkl, struct block_context **ctx)
|
||||
{
|
||||
int i;
|
||||
s64_t timestamp;
|
||||
|
||||
*ctx = NULL;
|
||||
timestamp = k_uptime_get();
|
||||
for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) {
|
||||
if (block1_contexts[i].tkl == 0) {
|
||||
*ctx = &block1_contexts[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (timestamp - block1_contexts[i].timestamp >
|
||||
TIMEOUT_BLOCKWISE_TRANSFER) {
|
||||
*ctx = &block1_contexts[i];
|
||||
/* TODO: notify application for block
|
||||
* transfer timeout
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*ctx == NULL) {
|
||||
SYS_LOG_ERR("Cannot find free block context");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
(*ctx)->tkl = tkl;
|
||||
memcpy((*ctx)->token, token, tkl);
|
||||
zoap_block_transfer_init(&(*ctx)->ctx, lwm2m_default_block_size(), 0);
|
||||
(*ctx)->timestamp = timestamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_block_ctx(const u8_t *token, u8_t tkl, struct block_context **ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
*ctx = NULL;
|
||||
|
||||
for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) {
|
||||
if (block1_contexts[i].tkl == tkl &&
|
||||
memcmp(token, block1_contexts[i].token, tkl) == 0) {
|
||||
*ctx = &block1_contexts[i];
|
||||
/* refresh timestmap */
|
||||
(*ctx)->timestamp = k_uptime_get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*ctx == NULL) {
|
||||
SYS_LOG_ERR("Cannot find block context");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_block_ctx(struct block_context *ctx)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->tkl = 0;
|
||||
}
|
||||
|
||||
/* observer functions */
|
||||
|
||||
int lwm2m_notify_observer(u16_t obj_id, u16_t obj_inst_id, u16_t res_id)
|
||||
|
@ -530,6 +641,20 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id)
|
|||
|
||||
/* utility functions */
|
||||
|
||||
static int get_option_int(const struct zoap_packet *zpkt, u8_t opt)
|
||||
{
|
||||
struct zoap_option option = {};
|
||||
u16_t count = 1;
|
||||
int r;
|
||||
|
||||
r = zoap_find_options(zpkt, opt, &option, count);
|
||||
if (r <= 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return zoap_option_value_to_int(&option);
|
||||
}
|
||||
|
||||
static void engine_clear_context(struct lwm2m_engine_context *context)
|
||||
{
|
||||
if (context->in) {
|
||||
|
@ -1698,6 +1823,12 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
|
|||
void *data_ptr = NULL;
|
||||
size_t data_len = 0;
|
||||
size_t len = 0;
|
||||
size_t total_size = 0;
|
||||
int ret = 0;
|
||||
u8_t tkl = 0;
|
||||
const u8_t *token;
|
||||
bool last_block = true;
|
||||
struct block_context *block_ctx = NULL;
|
||||
|
||||
if (!obj_inst || !res || !obj_field || !context) {
|
||||
return -EINVAL;
|
||||
|
@ -1719,8 +1850,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
|
|||
data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, &data_len);
|
||||
}
|
||||
|
||||
/* TODO: check for block transfer fields here */
|
||||
|
||||
if (data_ptr && data_len > 0) {
|
||||
switch (obj_field->data_type) {
|
||||
|
||||
|
@ -1808,14 +1937,30 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
|
|||
}
|
||||
|
||||
if (res->post_write_cb) {
|
||||
/* Get block1 option for checking MORE block flag */
|
||||
ret = get_option_int(in->in_zpkt, ZOAP_OPTION_BLOCK1);
|
||||
if (ret >= 0) {
|
||||
last_block = !GET_MORE(ret);
|
||||
|
||||
/* Get block_ctx for total_size (might be zero) */
|
||||
token = zoap_header_get_token(in->in_zpkt, &tkl);
|
||||
if (token != NULL &&
|
||||
!get_block_ctx(token, tkl, &block_ctx)) {
|
||||
total_size = block_ctx->ctx.total_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* ignore return value here */
|
||||
res->post_write_cb(obj_inst->obj_inst_id, data_ptr, len,
|
||||
false, 0);
|
||||
ret = res->post_write_cb(obj_inst->obj_inst_id, data_ptr, len,
|
||||
last_block, total_size);
|
||||
if (ret >= 0) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NOTIFY_OBSERVER_PATH(path);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lwm2m_write_attr_handler(struct lwm2m_engine_obj *obj,
|
||||
|
@ -2103,20 +2248,6 @@ static int do_write_op(struct lwm2m_engine_obj *obj,
|
|||
}
|
||||
}
|
||||
|
||||
static int get_observe_option(const struct zoap_packet *zpkt)
|
||||
{
|
||||
struct zoap_option option = {};
|
||||
u16_t count = 1;
|
||||
int r;
|
||||
|
||||
r = zoap_find_options(zpkt, ZOAP_OPTION_OBSERVE, &option, count);
|
||||
if (r <= 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return zoap_option_value_to_int(&option);
|
||||
}
|
||||
|
||||
static int handle_request(struct zoap_packet *request,
|
||||
struct lwm2m_message *msg)
|
||||
{
|
||||
|
@ -2133,6 +2264,9 @@ static int handle_request(struct zoap_packet *request,
|
|||
struct lwm2m_engine_context context;
|
||||
int observe = -1; /* default to -1, 0 = ENABLE, 1 = DISABLE */
|
||||
bool discover = false;
|
||||
struct block_context *block_ctx = NULL;
|
||||
size_t block_offset = 0;
|
||||
enum zoap_block_size block_size;
|
||||
|
||||
/* setup engine context */
|
||||
memset(&context, 0, sizeof(struct lwm2m_engine_context));
|
||||
|
@ -2208,7 +2342,7 @@ static int handle_request(struct zoap_packet *request,
|
|||
context.operation = LWM2M_OP_READ;
|
||||
}
|
||||
/* check for observe */
|
||||
observe = get_observe_option(in.in_zpkt);
|
||||
observe = get_option_int(in.in_zpkt, ZOAP_OPTION_OBSERVE);
|
||||
zoap_header_set_code(out.out_zpkt, ZOAP_RESPONSE_CODE_CONTENT);
|
||||
break;
|
||||
|
||||
|
@ -2245,7 +2379,31 @@ static int handle_request(struct zoap_packet *request,
|
|||
in.inpos = 0;
|
||||
in.inbuf = zoap_packet_get_payload(in.in_zpkt, &in.insize);
|
||||
|
||||
/* TODO: check for block transfer? */
|
||||
/* Check for block transfer */
|
||||
r = get_option_int(in.in_zpkt, ZOAP_OPTION_BLOCK1);
|
||||
if (r > 0) {
|
||||
/* RFC7252: 4.6. Message Size */
|
||||
block_size = GET_BLOCK_SIZE(r);
|
||||
if (GET_MORE(r) &&
|
||||
zoap_block_size_to_bytes(block_size) > in.insize) {
|
||||
SYS_LOG_DBG("Trailing payload is discarded!");
|
||||
r = -EFBIG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (GET_BLOCK_NUM(r) == 0) {
|
||||
r = init_block_ctx(token, tkl, &block_ctx);
|
||||
} else {
|
||||
r = get_block_ctx(token, tkl, &block_ctx);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* 0 will be returned if it's the last block */
|
||||
block_offset = zoap_next_block(in.in_zpkt, &block_ctx->ctx);
|
||||
}
|
||||
|
||||
switch (context.operation) {
|
||||
|
||||
|
@ -2315,8 +2473,30 @@ static int handle_request(struct zoap_packet *request,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
/* TODO: Handle blockwise 1 */
|
||||
if (r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Handle blockwise 1 */
|
||||
if (block_ctx) {
|
||||
if (block_offset > 0) {
|
||||
/* More to come, ack with correspond block # */
|
||||
r = zoap_add_block1_option(
|
||||
out.out_zpkt, &block_ctx->ctx);
|
||||
if (r) {
|
||||
/* report as internal server error */
|
||||
SYS_LOG_ERR("Fail adding block1 option: %d", r);
|
||||
r = -EINVAL;
|
||||
goto error;
|
||||
} else {
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_CONTINUE);
|
||||
}
|
||||
} else {
|
||||
/* Free context when finished */
|
||||
free_block_ctx(block_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (out.outlen > 0) {
|
||||
SYS_LOG_DBG("replying with %u bytes", out.outlen);
|
||||
|
@ -2324,28 +2504,32 @@ static int handle_request(struct zoap_packet *request,
|
|||
} else {
|
||||
SYS_LOG_DBG("no data in reply");
|
||||
}
|
||||
} else {
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (r == -ENOENT) {
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_NOT_FOUND);
|
||||
r = 0;
|
||||
} else if (r == -EPERM) {
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_NOT_ALLOWED);
|
||||
r = 0;
|
||||
} else if (r == -EEXIST) {
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_BAD_REQUEST);
|
||||
r = 0;
|
||||
} else if (r == -EFBIG) {
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_REQUEST_TOO_LARGE);
|
||||
} else {
|
||||
/* Failed to handle the request */
|
||||
zoap_header_set_code(out.out_zpkt,
|
||||
ZOAP_RESPONSE_CODE_INTERNAL_ERROR);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
/* Free block context when error happened */
|
||||
free_block_ctx(block_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
|
||||
|
@ -2788,6 +2972,9 @@ error_start:
|
|||
|
||||
static int lwm2m_engine_init(struct device *dev)
|
||||
{
|
||||
memset(block1_contexts, 0,
|
||||
sizeof(struct block_context) * NUM_BLOCK1_CONTEXT);
|
||||
|
||||
/* start thread to handle OBSERVER / NOTIFY events */
|
||||
k_thread_create(&engine_thread_data,
|
||||
&engine_thread_stack[0],
|
||||
|
|
|
@ -103,6 +103,8 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
|
|||
bool handle_separate_response,
|
||||
udp_request_handler_cb_t udp_request_handler);
|
||||
|
||||
enum zoap_block_size lwm2m_default_block_size(void);
|
||||
|
||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)
|
||||
u8_t lwm2m_firmware_get_update_state(void);
|
||||
void lwm2m_firmware_set_update_state(u8_t state);
|
||||
|
|
|
@ -181,13 +181,41 @@ static int package_write_cb(u16_t obj_inst_id,
|
|||
u8_t *data, u16_t data_len,
|
||||
bool last_block, size_t total_size)
|
||||
{
|
||||
SYS_LOG_DBG("PACKAGE WRITE");
|
||||
if (write_cb) {
|
||||
write_cb(obj_inst_id, data, data_len, last_block, total_size);
|
||||
u8_t state;
|
||||
int ret = 0;
|
||||
|
||||
state = lwm2m_firmware_get_update_state();
|
||||
if (state == STATE_IDLE) {
|
||||
/* TODO: setup timer to check download status,
|
||||
* make sure it fail after timeout
|
||||
*/
|
||||
lwm2m_firmware_set_update_state(STATE_DOWNLOADING);
|
||||
} else if (state != STATE_DOWNLOADING) {
|
||||
if (data_len == 0 && state == STATE_DOWNLOADED) {
|
||||
/* reset to state idle and result default */
|
||||
lwm2m_firmware_set_update_result(RESULT_DEFAULT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
SYS_LOG_DBG("Cannot download: state = %d", state);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (write_cb) {
|
||||
ret = write_cb(obj_inst_id, data, data_len,
|
||||
last_block, total_size);
|
||||
if (ret < 0) {
|
||||
SYS_LOG_ERR("Failed to store firmware: %d", ret);
|
||||
lwm2m_firmware_set_update_result(
|
||||
RESULT_INTEGRITY_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
if (last_block) {
|
||||
lwm2m_firmware_set_update_state(STATE_DOWNLOADED);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int package_uri_write_cb(u16_t obj_inst_id,
|
||||
|
|
|
@ -225,28 +225,6 @@ do_firmware_transfer_reply_cb(const struct zoap_packet *response,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static enum zoap_block_size default_block_size(void)
|
||||
{
|
||||
switch (CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_BLOCK_SIZE) {
|
||||
case 16:
|
||||
return ZOAP_BLOCK_16;
|
||||
case 32:
|
||||
return ZOAP_BLOCK_32;
|
||||
case 64:
|
||||
return ZOAP_BLOCK_64;
|
||||
case 128:
|
||||
return ZOAP_BLOCK_128;
|
||||
case 256:
|
||||
return ZOAP_BLOCK_256;
|
||||
case 512:
|
||||
return ZOAP_BLOCK_512;
|
||||
case 1024:
|
||||
return ZOAP_BLOCK_1024;
|
||||
}
|
||||
|
||||
return ZOAP_BLOCK_256;
|
||||
}
|
||||
|
||||
static void firmware_transfer(struct k_work *work)
|
||||
{
|
||||
int ret, family;
|
||||
|
@ -325,7 +303,8 @@ static void firmware_transfer(struct k_work *work)
|
|||
}
|
||||
|
||||
/* reset block transfer context */
|
||||
zoap_block_transfer_init(&firmware_block_ctx, default_block_size(), 0);
|
||||
zoap_block_transfer_init(&firmware_block_ctx,
|
||||
lwm2m_default_block_size(), 0);
|
||||
transfer_request(&firmware_block_ctx, NULL, 0,
|
||||
do_firmware_transfer_reply_cb);
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue