add ota algorithm for device
1. effective "Differential Upgrade" patch algorithm with high compression rate 2. effective recovery algorithm support recovery firmware in blocks which has low memory consumption and wear-leveling strategies, especially suitable for embeded devices with low RAM. 3. add sample ota bootloader project, see: board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_bootloader_recovery 4. add sample application project for download firmware through http, see: board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_http 5. add sample application project for download firmware through qcloud explorer console, see: board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_qcloud_iot_explorer 6. an OTA markdown document is pending
This commit is contained in:
561
components/ota/common/diff/graph.c
Normal file
561
components/ota/common/diff/graph.c
Normal file
@@ -0,0 +1,561 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
* Tencent is pleased to support the open source community by making TencentOS
|
||||
* available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* If you have downloaded a copy of the TencentOS binary from Tencent, please
|
||||
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
|
||||
*
|
||||
* If you have downloaded a copy of the TencentOS source code from Tencent,
|
||||
* please note that TencentOS source code is licensed under the BSD 3-Clause
|
||||
* License, except for the third-party components listed below which are
|
||||
* subject to different license terms. Your integration of TencentOS into your
|
||||
* own projects may require compliance with the BSD 3-Clause License, as well
|
||||
* as the other licenses applicable to the third-party components included
|
||||
* within TencentOS.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "assert.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "graph.h"
|
||||
|
||||
int graph_create(graph_t *graph, int vertexs_n)
|
||||
{
|
||||
int i = 0;
|
||||
vertex_t *vertexs;
|
||||
|
||||
if (!graph || vertexs_n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(graph, 0, sizeof(graph_t));
|
||||
|
||||
if ((vertexs = malloc(vertexs_n * sizeof(vertex_t))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(vertexs, 0, vertexs_n * sizeof(vertex_t));
|
||||
|
||||
for (i = 0; i < vertexs_n; ++i) {
|
||||
list_init(&vertexs[i].first_in);
|
||||
list_init(&vertexs[i].first_out);
|
||||
}
|
||||
|
||||
graph->edges_n = 0;
|
||||
graph->vertexs_n = vertexs_n;
|
||||
graph->vertexs = vertexs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_destroy(graph_t *graph)
|
||||
{
|
||||
int i = 0;
|
||||
vertex_t *vertex;
|
||||
edge_t *edge, *tmp;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->vertexs_n; ++i) {
|
||||
vertex = &graph->vertexs[i];
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, tail_list, &vertex->first_out) {
|
||||
list_del(&edge->tail_list);
|
||||
free(edge);
|
||||
}
|
||||
}
|
||||
|
||||
free(graph->vertexs);
|
||||
|
||||
graph->edges_n = 0;
|
||||
graph->vertexs_n = 0;
|
||||
graph->vertexs = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_edge_add(graph_t *graph, int tail_vertex, int head_vertex)
|
||||
{
|
||||
edge_t *edge;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tail_vertex >= graph->vertexs_n ||
|
||||
head_vertex >= graph->vertexs_n ||
|
||||
tail_vertex < 0 ||
|
||||
head_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((edge = malloc(sizeof(edge_t))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
edge->head_vertex = head_vertex;
|
||||
edge->tail_vertex = tail_vertex;
|
||||
list_init(&edge->head_list);
|
||||
list_init(&edge->tail_list);
|
||||
|
||||
tail_v = &graph->vertexs[tail_vertex];
|
||||
head_v = &graph->vertexs[head_vertex];
|
||||
|
||||
list_add(&edge->tail_list, &tail_v->first_out);
|
||||
++tail_v->out_degree;
|
||||
|
||||
list_add(&edge->head_list, &head_v->first_in);
|
||||
++head_v->in_degree;
|
||||
|
||||
++graph->edges_n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_edge_rmv(graph_t *graph, int tail_vertex, int head_vertex)
|
||||
{
|
||||
edge_t *edge, *tmp;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tail_vertex >= graph->vertexs_n ||
|
||||
head_vertex >= graph->vertexs_n ||
|
||||
tail_vertex < 0 ||
|
||||
head_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tail_v = &graph->vertexs[tail_vertex];
|
||||
head_v = &graph->vertexs[head_vertex];
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, tail_list, &tail_v->first_out) {
|
||||
if (edge->tail_vertex == tail_vertex &&
|
||||
edge->head_vertex == head_vertex) {
|
||||
list_del(&edge->tail_list);
|
||||
--tail_v->out_degree;
|
||||
|
||||
list_del(&edge->head_list);
|
||||
--head_v->in_degree;
|
||||
|
||||
free(edge);
|
||||
--graph->edges_n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int graph_edge_rmv_by_tail(graph_t *graph, int tail_vertex, graph_edge_delete_cb del_cb, void *cb_arg)
|
||||
{
|
||||
edge_t *edge, *tmp;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tail_vertex >= graph->vertexs_n || tail_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tail_v = &graph->vertexs[tail_vertex];
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, tail_list, &tail_v->first_out) {
|
||||
if (edge->tail_vertex == tail_vertex) {
|
||||
list_del(&edge->tail_list);
|
||||
--tail_v->out_degree;
|
||||
|
||||
list_del(&edge->head_list);
|
||||
head_v = &graph->vertexs[edge->head_vertex];
|
||||
--head_v->in_degree;
|
||||
|
||||
if (del_cb) {
|
||||
del_cb(edge->tail_vertex, edge->head_vertex, cb_arg);
|
||||
}
|
||||
|
||||
free(edge);
|
||||
--graph->edges_n;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_edge_rmv_one_by_tail(graph_t *graph, int tail_vertex)
|
||||
{
|
||||
edge_t *edge, *tmp;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tail_vertex >= graph->vertexs_n || tail_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tail_v = &graph->vertexs[tail_vertex];
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, tail_list, &tail_v->first_out) {
|
||||
if (edge->tail_vertex == tail_vertex) {
|
||||
list_del(&edge->tail_list);
|
||||
--tail_v->out_degree;
|
||||
|
||||
list_del(&edge->head_list);
|
||||
head_v = &graph->vertexs[edge->head_vertex];
|
||||
--head_v->in_degree;
|
||||
|
||||
free(edge);
|
||||
--graph->edges_n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int graph_edge_rmv_by_head(graph_t *graph, int head_vertex, graph_edge_delete_cb del_cb, void *cb_arg)
|
||||
{
|
||||
edge_t *edge, *tmp;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (head_vertex >= graph->vertexs_n || head_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
head_v = &graph->vertexs[head_vertex];
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, head_list, &head_v->first_in) {
|
||||
if (edge->head_vertex == head_vertex) {
|
||||
list_del(&edge->tail_list);
|
||||
tail_v = &graph->vertexs[edge->tail_vertex];
|
||||
--tail_v->out_degree;
|
||||
|
||||
list_del(&edge->head_list);
|
||||
--head_v->in_degree;
|
||||
|
||||
if (del_cb) {
|
||||
del_cb(edge->tail_vertex, edge->head_vertex, cb_arg);
|
||||
}
|
||||
|
||||
free(edge);
|
||||
--graph->edges_n;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_edge_rmv_one_by_head(graph_t *graph, int head_vertex)
|
||||
{
|
||||
edge_t *edge, *tmp;
|
||||
vertex_t *tail_v, *head_v;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (head_vertex >= graph->vertexs_n || head_vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
head_v = &graph->vertexs[head_vertex];
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(edge, tmp, edge_t, head_list, &head_v->first_in) {
|
||||
if (edge->head_vertex == head_vertex) {
|
||||
list_del(&edge->tail_list);
|
||||
tail_v = &graph->vertexs[edge->tail_vertex];
|
||||
--tail_v->out_degree;
|
||||
|
||||
list_del(&edge->head_list);
|
||||
--head_v->in_degree;
|
||||
|
||||
free(edge);
|
||||
--graph->edges_n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int graph_edgesn_get(graph_t *graph)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return graph->edges_n;
|
||||
}
|
||||
|
||||
int graph_vertex_max(graph_t *graph)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return graph->vertexs_n;
|
||||
}
|
||||
|
||||
int graph_indegree_get(graph_t *graph, int vertex)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vertex >= graph->vertexs_n || vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return graph->vertexs[vertex].in_degree;
|
||||
}
|
||||
|
||||
int graph_outdegree_get(graph_t *graph, int vertex)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vertex >= graph->vertexs_n || vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return graph->vertexs[vertex].out_degree;
|
||||
}
|
||||
|
||||
int graph_tag_set(graph_t *graph, int vertex, v_tag_t tag)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vertex >= graph->vertexs_n || vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
graph->vertexs[vertex].tag = tag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_tag_reset(graph_t *graph, int vertex)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vertex >= graph->vertexs_n || vertex < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
graph->vertexs[vertex].tag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
v_tag_t graph_tag_get(graph_t *graph, int vertex)
|
||||
{
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return (v_tag_t)-1;
|
||||
}
|
||||
|
||||
if (vertex >= graph->vertexs_n || vertex < 0) {
|
||||
return (v_tag_t)-1;
|
||||
}
|
||||
|
||||
return graph->vertexs[vertex].tag;
|
||||
}
|
||||
|
||||
int graph_dfs_create(dfs_t *dfs, graph_t *graph)
|
||||
{
|
||||
if (!dfs || !graph) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (graph_vertex_max(graph) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(dfs, 0, sizeof(dfs_t));
|
||||
|
||||
if (stack_create(&dfs->stack, graph_vertex_max(graph)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stack_push(&dfs->stack, 0) != 0) {
|
||||
// push the first vertex of the graph into the stack
|
||||
return -1;
|
||||
}
|
||||
|
||||
graph_vertex_set_visited(graph, 0);
|
||||
|
||||
dfs->graph = graph;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_dfs_destroy(dfs_t *dfs)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!dfs || !dfs->graph) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph_vertex_max(dfs->graph); ++i) {
|
||||
graph_tag_reset(dfs->graph, i);
|
||||
}
|
||||
|
||||
stack_destroy(&dfs->stack);
|
||||
|
||||
dfs->graph = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_dfs_has_next(dfs_t *dfs)
|
||||
{
|
||||
if (!dfs || !dfs->graph) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return !stack_is_empty(&dfs->stack);
|
||||
}
|
||||
|
||||
int graph_dfs_ring_detect(dfs_t *dfs, int *ring_size)
|
||||
{
|
||||
int i = 0;
|
||||
edge_t *edge;
|
||||
graph_t *graph;
|
||||
vertex_t *vertex;
|
||||
int vertex_idx, the_ring_size = 0, is_found = 0;
|
||||
|
||||
assert(sizeof(int) == sizeof(element_type_t));
|
||||
|
||||
if (!dfs || !dfs->graph || !ring_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
graph = dfs->graph;
|
||||
|
||||
while (!stack_is_empty(&dfs->stack)) {
|
||||
vertex_idx = stack_top(&dfs->stack);
|
||||
vertex = &graph->vertexs[vertex_idx];
|
||||
|
||||
is_found = 0;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(edge, edge_t, tail_list, &vertex->first_out) {
|
||||
if (!graph_vertex_is_visited(graph, edge->head_vertex)) {
|
||||
// still fresh neighbors here
|
||||
stack_push(&dfs->stack, edge->head_vertex);
|
||||
graph_vertex_set_visited(graph, edge->head_vertex);
|
||||
is_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (graph_vertex_is_tnode(graph, edge->head_vertex) ||
|
||||
graph_vertex_is_rnode(graph, edge->head_vertex)) {
|
||||
// already detected as a ring or a terminal node
|
||||
continue;
|
||||
}
|
||||
|
||||
// set DFS_RING_NODE tag
|
||||
graph_vertex_set_rnode(graph, edge->head_vertex);
|
||||
|
||||
// if reach here, a ring is detected
|
||||
stack_peek_init(&dfs->stack);
|
||||
while ((vertex_idx = stack_peek(&dfs->stack)) != -1) {
|
||||
++the_ring_size;
|
||||
if (vertex_idx == edge->head_vertex) {
|
||||
*ring_size = the_ring_size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no fresh neighbors anymore
|
||||
if (!is_found) {
|
||||
stack_pop(&dfs->stack);
|
||||
graph_vertex_set_tnode(graph, vertex_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/* if here, graph may still has isolated nodes there: multi-connected-component in the graph */
|
||||
for (i = 0; i < graph_vertex_max(graph); ++i) {
|
||||
if (!graph_vertex_is_visited(graph, i)) {
|
||||
stack_push(&dfs->stack, i);
|
||||
graph_vertex_set_visited(graph, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int graph_out_print(graph_t *graph)
|
||||
{
|
||||
int i = 0;
|
||||
edge_t *edge;
|
||||
vertex_t *vertex;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->vertexs_n; ++i) {
|
||||
vertex = &graph->vertexs[i];
|
||||
|
||||
if (vertex->out_degree == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("\nvertex: %d\n", i);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(edge, edge_t, tail_list, &vertex->first_out) {
|
||||
printf(" - %d -> %d\n", edge->tail_vertex, edge->head_vertex);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int graph_in_print(graph_t *graph)
|
||||
{
|
||||
int i = 0;
|
||||
edge_t *edge;
|
||||
vertex_t *vertex;
|
||||
|
||||
if (!graph || !graph->vertexs || !graph->vertexs_n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < graph->vertexs_n; ++i) {
|
||||
vertex = &graph->vertexs[i];
|
||||
|
||||
if (vertex->in_degree == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("\nvertex: %d\n", i);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(edge, edge_t, head_list, &vertex->first_in) {
|
||||
printf(" - %d -> %d\n", edge->tail_vertex, edge->head_vertex);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user