mirror of
https://github.com/ok-home/ota_ws_update.git
synced 2025-11-13 22:03:27 +03:00
ota
This commit is contained in:
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
# (Not part of the boilerplate)
|
# (Not part of the boilerplate)
|
||||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
#set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(ota)
|
project(ota_ws)
|
||||||
|
|||||||
23
include/ota_ws.h
Normal file
23
include/ota_ws.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ota_ws_private.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief register provision handlers ( web page & ws handlers) on existing httpd server with ws support
|
||||||
|
* uri page -> CONFIG_DEFAULT_URI
|
||||||
|
* @param httpd_handle_t server -> existing server handle
|
||||||
|
* @return
|
||||||
|
* ESP_OK -> register OK
|
||||||
|
* ESP_FAIL -> register FAIL
|
||||||
|
*/
|
||||||
|
esp_err_t ota_ws_register_uri_handler(httpd_handle_t server);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS
|
SRCS
|
||||||
|
example_ota_ws.c
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
"."
|
"."
|
||||||
EMBED_FILES
|
#EMBED_FILES
|
||||||
|
ota_ws.html
|
||||||
)
|
)
|
||||||
@@ -12,13 +12,6 @@
|
|||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_ota_ops.h"
|
#include "esp_ota_ops.h"
|
||||||
#include "esp_http_client.h"
|
|
||||||
#include "esp_https_ota.h"
|
|
||||||
#include "protocol_examples_common.h"
|
|
||||||
#include "string.h"
|
|
||||||
|
|
||||||
#include "nvs.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
|
|
||||||
//#include <esp_log.h>
|
//#include <esp_log.h>
|
||||||
@@ -26,9 +19,6 @@
|
|||||||
#include "prv_wifi_connect.h"
|
#include "prv_wifi_connect.h"
|
||||||
static const char *TAG = "ota_ws";
|
static const char *TAG = "ota_ws";
|
||||||
|
|
||||||
void example_echo_ws_server(void);
|
|
||||||
esp_err_t example_register_uri_handler(httpd_handle_t server);
|
|
||||||
|
|
||||||
#define MDNS
|
#define MDNS
|
||||||
#ifdef MDNS
|
#ifdef MDNS
|
||||||
#include "mdns.h"
|
#include "mdns.h"
|
||||||
@@ -62,6 +52,6 @@ void app_main(void)
|
|||||||
netbiosns_set_name("esp");
|
netbiosns_set_name("esp");
|
||||||
#endif // MDNS
|
#endif // MDNS
|
||||||
|
|
||||||
prv_start_http_server(PRV_MODE_STAY_ACTIVE,example_register_uri_handler); // run server
|
prv_start_http_server(PRV_MODE_STAY_ACTIVE,NULL); // run server
|
||||||
//example_echo_ws_server();
|
//example_echo_ws_server();
|
||||||
}
|
}
|
||||||
530
private_include/jsmn.h
Normal file
530
private_include/jsmn.h
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 Serge Zaitsev
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef JSMN_H
|
||||||
|
#define JSMN_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSMN_STATIC
|
||||||
|
|
||||||
|
#ifdef JSMN_STATIC
|
||||||
|
#define JSMN_API static
|
||||||
|
#else
|
||||||
|
#define JSMN_API extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON type identifier. Basic types are:
|
||||||
|
* o Object
|
||||||
|
* o Array
|
||||||
|
* o String
|
||||||
|
* o Other primitive: number, boolean (true/false) or null
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JSMN_UNDEFINED = 0,
|
||||||
|
JSMN_OBJECT = 1,
|
||||||
|
JSMN_ARRAY = 2,
|
||||||
|
JSMN_STRING = 3,
|
||||||
|
JSMN_PRIMITIVE = 4
|
||||||
|
} jsmntype_t;
|
||||||
|
|
||||||
|
enum jsmnerr
|
||||||
|
{
|
||||||
|
/* Not enough tokens were provided */
|
||||||
|
JSMN_ERROR_NOMEM = -1,
|
||||||
|
/* Invalid character inside JSON string */
|
||||||
|
JSMN_ERROR_INVAL = -2,
|
||||||
|
/* The string is not a full JSON packet, more bytes expected */
|
||||||
|
JSMN_ERROR_PART = -3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON token description.
|
||||||
|
* type type (object, array, string etc.)
|
||||||
|
* start start position in JSON data string
|
||||||
|
* end end position in JSON data string
|
||||||
|
*/
|
||||||
|
typedef struct jsmntok
|
||||||
|
{
|
||||||
|
jsmntype_t type;
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
int size;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
int parent;
|
||||||
|
#endif
|
||||||
|
} jsmntok_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON parser. Contains an array of token blocks available. Also stores
|
||||||
|
* the string being parsed now and current position in that string.
|
||||||
|
*/
|
||||||
|
typedef struct jsmn_parser
|
||||||
|
{
|
||||||
|
unsigned int pos; /* offset in the JSON string */
|
||||||
|
unsigned int toknext; /* next token to allocate */
|
||||||
|
int toksuper; /* superior token node, e.g. parent object or array */
|
||||||
|
} jsmn_parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create JSON parser over an array of tokens
|
||||||
|
*/
|
||||||
|
JSMN_API void jsmn_init(jsmn_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run JSON parser. It parses a JSON data string into and array of tokens, each
|
||||||
|
* describing
|
||||||
|
* a single JSON object.
|
||||||
|
*/
|
||||||
|
JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
|
||||||
|
jsmntok_t *tokens, const unsigned int num_tokens);
|
||||||
|
|
||||||
|
#ifndef JSMN_HEADER
|
||||||
|
/**
|
||||||
|
* Allocates a fresh unused token from the token pool.
|
||||||
|
*/
|
||||||
|
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
|
||||||
|
const size_t num_tokens)
|
||||||
|
{
|
||||||
|
jsmntok_t *tok;
|
||||||
|
if (parser->toknext >= num_tokens)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tok = &tokens[parser->toknext++];
|
||||||
|
tok->start = tok->end = -1;
|
||||||
|
tok->size = 0;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
tok->parent = -1;
|
||||||
|
#endif
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills token type and boundaries.
|
||||||
|
*/
|
||||||
|
static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
|
||||||
|
const int start, const int end)
|
||||||
|
{
|
||||||
|
token->type = type;
|
||||||
|
token->start = start;
|
||||||
|
token->end = end;
|
||||||
|
token->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills next available token with JSON primitive.
|
||||||
|
*/
|
||||||
|
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
||||||
|
const size_t len, jsmntok_t *tokens,
|
||||||
|
const size_t num_tokens)
|
||||||
|
{
|
||||||
|
jsmntok_t *token;
|
||||||
|
int start;
|
||||||
|
|
||||||
|
start = parser->pos;
|
||||||
|
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
|
||||||
|
{
|
||||||
|
switch (js[parser->pos])
|
||||||
|
{
|
||||||
|
#ifndef JSMN_STRICT
|
||||||
|
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
||||||
|
case ':':
|
||||||
|
#endif
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case ' ':
|
||||||
|
case ',':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
goto found;
|
||||||
|
default:
|
||||||
|
/* to quiet a warning from gcc*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (js[parser->pos] < 32 || js[parser->pos] >= 127)
|
||||||
|
{
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* In strict mode primitive must be followed by a comma/object/array */
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
found:
|
||||||
|
if (tokens == NULL)
|
||||||
|
{
|
||||||
|
parser->pos--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
}
|
||||||
|
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
parser->pos--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills next token with JSON string.
|
||||||
|
*/
|
||||||
|
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
||||||
|
const size_t len, jsmntok_t *tokens,
|
||||||
|
const size_t num_tokens)
|
||||||
|
{
|
||||||
|
jsmntok_t *token;
|
||||||
|
|
||||||
|
int start = parser->pos;
|
||||||
|
|
||||||
|
parser->pos++;
|
||||||
|
|
||||||
|
/* Skip starting quote */
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
|
||||||
|
{
|
||||||
|
char c = js[parser->pos];
|
||||||
|
|
||||||
|
/* Quote: end of string */
|
||||||
|
if (c == '\"')
|
||||||
|
{
|
||||||
|
if (tokens == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
}
|
||||||
|
jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Backslash: Quoted symbol expected */
|
||||||
|
if (c == '\\' && parser->pos + 1 < len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
parser->pos++;
|
||||||
|
switch (js[parser->pos])
|
||||||
|
{
|
||||||
|
/* Allowed escaped symbols */
|
||||||
|
case '\"':
|
||||||
|
case '/':
|
||||||
|
case '\\':
|
||||||
|
case 'b':
|
||||||
|
case 'f':
|
||||||
|
case 'r':
|
||||||
|
case 'n':
|
||||||
|
case 't':
|
||||||
|
break;
|
||||||
|
/* Allows escaped symbol \uXXXX */
|
||||||
|
case 'u':
|
||||||
|
parser->pos++;
|
||||||
|
for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
/* If it isn't a hex character we have an error */
|
||||||
|
if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
||||||
|
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
||||||
|
(js[parser->pos] >= 97 && js[parser->pos] <= 102)))
|
||||||
|
{ /* a-f */
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
parser->pos++;
|
||||||
|
}
|
||||||
|
parser->pos--;
|
||||||
|
break;
|
||||||
|
/* Unexpected symbol */
|
||||||
|
default:
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse JSON string and fill tokens.
|
||||||
|
*/
|
||||||
|
JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
|
||||||
|
jsmntok_t *tokens, const unsigned int num_tokens)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
int i;
|
||||||
|
jsmntok_t *token;
|
||||||
|
int count = parser->toknext;
|
||||||
|
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
jsmntype_t type;
|
||||||
|
|
||||||
|
c = js[parser->pos];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
count++;
|
||||||
|
if (tokens == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
}
|
||||||
|
if (parser->toksuper != -1)
|
||||||
|
{
|
||||||
|
jsmntok_t *t = &tokens[parser->toksuper];
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* In strict mode an object or array can't become a key */
|
||||||
|
if (t->type == JSMN_OBJECT)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
t->size++;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||||
|
token->start = parser->pos;
|
||||||
|
parser->toksuper = parser->toknext - 1;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
if (tokens == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
if (parser->toknext < 1)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
token = &tokens[parser->toknext - 1];
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (token->start != -1 && token->end == -1)
|
||||||
|
{
|
||||||
|
if (token->type != type)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
token->end = parser->pos + 1;
|
||||||
|
parser->toksuper = token->parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (token->parent == -1)
|
||||||
|
{
|
||||||
|
if (token->type != type || parser->toksuper == -1)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = &tokens[token->parent];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
token = &tokens[i];
|
||||||
|
if (token->start != -1 && token->end == -1)
|
||||||
|
{
|
||||||
|
if (token->type != type)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
parser->toksuper = -1;
|
||||||
|
token->end = parser->pos + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Error if unmatched closing bracket */
|
||||||
|
if (i == -1)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
for (; i >= 0; i--)
|
||||||
|
{
|
||||||
|
token = &tokens[i];
|
||||||
|
if (token->start != -1 && token->end == -1)
|
||||||
|
{
|
||||||
|
parser->toksuper = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if (parser->toksuper != -1 && tokens != NULL)
|
||||||
|
{
|
||||||
|
tokens[parser->toksuper].size++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case ' ':
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
parser->toksuper = parser->toknext - 1;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (tokens != NULL && parser->toksuper != -1 &&
|
||||||
|
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
||||||
|
tokens[parser->toksuper].type != JSMN_OBJECT)
|
||||||
|
{
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
parser->toksuper = tokens[parser->toksuper].parent;
|
||||||
|
#else
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT)
|
||||||
|
{
|
||||||
|
if (tokens[i].start != -1 && tokens[i].end == -1)
|
||||||
|
{
|
||||||
|
parser->toksuper = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* In strict mode primitives are: numbers and booleans */
|
||||||
|
case '-':
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
case 't':
|
||||||
|
case 'f':
|
||||||
|
case 'n':
|
||||||
|
/* And they must not be keys of the object */
|
||||||
|
if (tokens != NULL && parser->toksuper != -1)
|
||||||
|
{
|
||||||
|
const jsmntok_t *t = &tokens[parser->toksuper];
|
||||||
|
if (t->type == JSMN_OBJECT ||
|
||||||
|
(t->type == JSMN_STRING && t->size != 0))
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* In non-strict mode every unquoted value is a primitive */
|
||||||
|
default:
|
||||||
|
#endif
|
||||||
|
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if (parser->toksuper != -1 && tokens != NULL)
|
||||||
|
{
|
||||||
|
tokens[parser->toksuper].size++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* Unexpected char in strict mode */
|
||||||
|
default:
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens != NULL)
|
||||||
|
{
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
/* Unmatched opened object or array */
|
||||||
|
if (tokens[i].start != -1 && tokens[i].end == -1)
|
||||||
|
{
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new parser based over a given buffer with an array of tokens
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
JSMN_API void jsmn_init(jsmn_parser *parser)
|
||||||
|
{
|
||||||
|
parser->pos = 0;
|
||||||
|
parser->toknext = 0;
|
||||||
|
parser->toksuper = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* JSMN_HEADER */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* JSMN_H */
|
||||||
7
private_include/ota_ws_private.h
Normal file
7
private_include/ota_ws_private.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include <esp_log.h>
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include "esp_http_server.h"
|
||||||
96
source/ota_esp.c
Normal file
96
source/ota_esp.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
#include "esp_ota_ops.h"
|
||||||
|
#include "esp_flash_partitions.h"
|
||||||
|
#include "esp_partition.h"
|
||||||
|
|
||||||
|
static const char *TAG = "ota_esp";
|
||||||
|
/*an ota data write buffer ready to write to the flash*/
|
||||||
|
//static char ota_write_data[BUFFSIZE + 1] = {0};
|
||||||
|
static const esp_partition_t *update_partition = NULL;
|
||||||
|
static bool image_header_was_checked = false;
|
||||||
|
static int binary_file_length = 0;
|
||||||
|
static esp_ota_handle_t update_handle = 0;
|
||||||
|
|
||||||
|
esp_err_t start_ota(void)
|
||||||
|
{
|
||||||
|
// return ESP_OK; // debug return
|
||||||
|
|
||||||
|
esp_err_t err;
|
||||||
|
ESP_LOGI(TAG, "Starting OTA");
|
||||||
|
|
||||||
|
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||||
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||||
|
|
||||||
|
if (configured != running)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
|
||||||
|
configured->address, running->address);
|
||||||
|
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||||
|
running->type, running->subtype, running->address);
|
||||||
|
|
||||||
|
update_partition = esp_ota_get_next_update_partition(NULL);
|
||||||
|
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
|
||||||
|
update_partition->subtype, update_partition->address);
|
||||||
|
|
||||||
|
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "esp_ota_begin failed ");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "esp_ota_begin succeeded");
|
||||||
|
|
||||||
|
image_header_was_checked = false;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t write_ota(int data_read, uint8_t *ota_write_data)
|
||||||
|
{
|
||||||
|
// return data_read; // debug return
|
||||||
|
|
||||||
|
if (image_header_was_checked == false) // first segment
|
||||||
|
{
|
||||||
|
esp_app_desc_t new_app_info;
|
||||||
|
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t))
|
||||||
|
{
|
||||||
|
// check current version with downloading
|
||||||
|
memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
|
||||||
|
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
|
||||||
|
|
||||||
|
image_header_was_checked = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "received package is not fit len");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
esp_err_t err = esp_ota_write(update_handle, (const void *)ota_write_data, data_read);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
binary_file_length += data_read;
|
||||||
|
ESP_LOGD(TAG, "Written image length %d", binary_file_length);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t end_ota(void)
|
||||||
|
{
|
||||||
|
esp_err_t err = esp_ota_end(update_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
|
||||||
|
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
err = esp_ota_set_boot_partition(update_partition);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
138
source/ota_ws.c
Normal file
138
source/ota_ws.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
#include "ota_ws_private.h"
|
||||||
|
#include "ota_ws.h"
|
||||||
|
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
|
||||||
|
#include "jsmn.h"
|
||||||
|
|
||||||
|
#define OTA_DEFAULT_WS_URI "/ws"
|
||||||
|
#define OTA_DEFAULT_URI "/"
|
||||||
|
|
||||||
|
static const char *TAG = "ota_ws";
|
||||||
|
|
||||||
|
// simple json parse -> only one parametr name/val
|
||||||
|
static esp_err_t json_to_str_parm(char *jsonstr, char *nameStr, char *valStr) // распаковать строку json в пару name/val
|
||||||
|
{
|
||||||
|
int r; // количество токенов
|
||||||
|
jsmn_parser p;
|
||||||
|
jsmntok_t t[5]; // только 2 пары параметров и obj
|
||||||
|
|
||||||
|
jsmn_init(&p);
|
||||||
|
r = jsmn_parse(&p, jsonstr, strlen(jsonstr), t, sizeof(t) / sizeof(t[0]));
|
||||||
|
if (r < 2)
|
||||||
|
{
|
||||||
|
valStr[0] = 0;
|
||||||
|
nameStr[0] = 0;
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
strncpy(nameStr, jsonstr + t[2].start, t[2].end - t[2].start);
|
||||||
|
nameStr[t[2].end - t[2].start] = 0;
|
||||||
|
if (r > 3)
|
||||||
|
{
|
||||||
|
strncpy(valStr, jsonstr + t[4].start, t[4].end - t[4].start);
|
||||||
|
valStr[t[4].end - t[4].start] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
valStr[0] = 0;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
static void send_json_string(char *str, httpd_req_t *req)
|
||||||
|
{
|
||||||
|
httpd_ws_frame_t ws_pkt;
|
||||||
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
|
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||||
|
ws_pkt.payload = (uint8_t *)str;
|
||||||
|
ws_pkt.len = strlen(str);
|
||||||
|
httpd_ws_send_frame(req, &ws_pkt);
|
||||||
|
}
|
||||||
|
// write wifi data from ws to nvs
|
||||||
|
static esp_err_t ota_ws_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
if (req->method == HTTP_GET)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Handshake done, the new connection was opened");
|
||||||
|
send_nvs_data(req); // read & send initial wifi data from nvs
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
httpd_ws_frame_t ws_pkt;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
|
// ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||||
|
/* Set max_len = 0 to get the frame len */
|
||||||
|
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 0);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "httpd_ws_recv_frame failed to get frame len with %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (ws_pkt.len)
|
||||||
|
{
|
||||||
|
/* ws_pkt.len + 1 is for NULL termination as we are expecting a string */
|
||||||
|
buf = calloc(1, ws_pkt.len + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Failed to calloc memory for buf");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
ws_pkt.payload = buf;
|
||||||
|
/* Set max_len = ws_pkt.len to get the frame payload */
|
||||||
|
ret = httpd_ws_recv_frame(req, &ws_pkt, ws_pkt.len);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "httpd_ws_recv_frame failed with %d", ret);
|
||||||
|
goto _recv_ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = ESP_OK;
|
||||||
|
if (ws_pkt.type == HTTPD_WS_TYPE_TEXT)
|
||||||
|
{
|
||||||
|
// json data
|
||||||
|
}
|
||||||
|
else if (ws_pkt.type == HTTPD_WS_TYPE_BIN)
|
||||||
|
{
|
||||||
|
// ota data
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "httpd_ws_recv_frame unknown frame type %d", ws_pkt.type);
|
||||||
|
ret = ESP_FAIL;
|
||||||
|
goto _recv_ret;
|
||||||
|
}
|
||||||
|
_recv_ret:
|
||||||
|
free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static esp_err_t ota_get_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
extern const unsigned char ota_ws_html_start[] asm("_binary_ota_ws_html_start");
|
||||||
|
extern const unsigned char ota_ws_html_end[] asm("_binary_ota_ws_html_end");
|
||||||
|
const size_t ota_ws_html_size = (ota_ws_html_end - ota_ws_html_start);
|
||||||
|
|
||||||
|
httpd_resp_send_chunk(req, (const char *)ota_ws_html_start, ota_ws_html_size);
|
||||||
|
httpd_resp_sendstr_chunk(req, NULL);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
static const httpd_uri_t gh = {
|
||||||
|
.uri = OTA_DEFAULT_URI,
|
||||||
|
.method = HTTP_GET,
|
||||||
|
.handler = ota_get_handler,
|
||||||
|
.user_ctx = NULL};
|
||||||
|
static const httpd_uri_t ws = {
|
||||||
|
.uri = OTA_DEFAULT_WS_URI,
|
||||||
|
.method = HTTP_GET,
|
||||||
|
.handler = ota_ws_handler,
|
||||||
|
.user_ctx = NULL,
|
||||||
|
.is_websocket = true};
|
||||||
|
esp_err_t ota_ws_register_uri_handler(httpd_handle_t server)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
ret = httpd_register_uri_handler(server, &gh);
|
||||||
|
if (ret)
|
||||||
|
goto _ret;
|
||||||
|
ret = httpd_register_uri_handler(server, &ws);
|
||||||
|
if (ret)
|
||||||
|
goto _ret;
|
||||||
|
_ret:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user