Unverified Commit 310faf7f authored by Terry Ellison's avatar Terry Ellison Committed by GitHub
Browse files

Merge pull request #2886 from nodemcu/dev

Next master drop
parents 68c425c0 a08e74d9
......@@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luac-cross", "luac-cross\luac-cross.vcxproj", "{78A3411A-A18F-41A4-B4A7-D76B273F0E44}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spiffsimg", "spiffsimg\spiffsimg.vcxproj", "{2DD84C09-254C-4884-A863-456EA1E32DCE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
......@@ -21,6 +23,14 @@ Global
{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x64.Build.0 = Release|x64
{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.ActiveCfg = Release|Win32
{78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.Build.0 = Release|Win32
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.ActiveCfg = Debug|x64
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.Build.0 = Debug|x64
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.ActiveCfg = Debug|Win32
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.Build.0 = Debug|Win32
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.ActiveCfg = Release|x64
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.Build.0 = Release|x64
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.ActiveCfg = Release|Win32
{2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
#ifndef __GETOPT_H__
/**
* DISCLAIMER
* This file is part of the mingw-w64 runtime package.
*
* The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define __GETOPT_H__
/* All the headers include this file. */
#include <crtdefs.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
#ifdef REPLACE_GETOPT
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
#undef optreset /* see getopt.h */
#define optreset __mingw_optreset
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
//extern int optind; /* index of first non-option in argv */
//extern int optopt; /* single option character, as parsed */
//extern int opterr; /* flag to enable built-in diagnostics... */
// /* (user may set to zero, to suppress) */
//
//extern char *optarg; /* pointer to argument of current option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#ifndef __CYGWIN__
#define __progname __argv[0]
#else
extern char __declspec(dllimport) *__progname;
#endif
#ifdef __CYGWIN__
static char EMSG[] = "";
#else
#define EMSG ""
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
static void
_vwarnx(const char *fmt,va_list ap)
{
(void)fprintf(stderr,"%s: ",__progname);
if (fmt != NULL)
(void)vfprintf(stderr,fmt,ap);
(void)fprintf(stderr,"\n");
}
static void
warnx(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
_vwarnx(fmt,ap);
va_end(ap);
}
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
//extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#endif /* !defined(__GETOPT_H__) */
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, ambiguous, match;
#define IDENTICAL_INTERPRETATION(_x, _y) \
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
long_options[(_x)].flag == long_options[(_y)].flag && \
long_options[(_x)].val == long_options[(_y)].val)
current_argv = place;
match = -1;
ambiguous = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
ambiguous = 0;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else if (!IDENTICAL_INTERPRETATION(i, match))
ambiguous = 1;
}
if (ambiguous) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
#undef IDENTICAL_INTERPRETATION
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
* optreset != 0 for GNU compatibility.
*/
if (posixly_correct == -1 || optreset != 0)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = (char*)strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
//extern int getopt_long(int nargc, char * const *nargv, const char *options,
// const struct option *long_options, int *idx);
//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
// const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{2DD84C09-254C-4884-A863-456EA1E32DCE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>spiffsimg</RootNamespace>
<WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>$(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<AdditionalDependencies>setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\app\spiffs\spiffs_cache.c" />
<ClCompile Include="..\..\app\spiffs\spiffs_check.c" />
<ClCompile Include="..\..\app\spiffs\spiffs_gc.c" />
<ClCompile Include="..\..\app\spiffs\spiffs_hydrogen.c" />
<ClCompile Include="..\..\app\spiffs\spiffs_nucleus.c" />
<ClCompile Include="..\..\tools\spiffsimg\main.c">
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4996</DisableSpecificWarnings>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\app\include\user_config.h" />
<ClInclude Include="..\..\app\platform\cpu_esp8266.h" />
<ClInclude Include="..\..\app\spiffs\nodemcu_spiffs.h" />
<ClInclude Include="..\..\app\spiffs\spiffs.h" />
<ClInclude Include="..\..\app\spiffs\spiffs_config.h" />
<ClInclude Include="..\..\app\spiffs\spiffs_nucleus.h" />
<ClInclude Include="..\..\tools\spiffsimg\spiffs_typedefs.h" />
<ClInclude Include="getopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="tools">
<UniqueIdentifier>{cc72cbf7-30a4-4c62-9413-509516a67c12}</UniqueIdentifier>
</Filter>
<Filter Include="tools\spiffsimg">
<UniqueIdentifier>{2796bdda-1fd8-4088-8d4e-41fdd71d5170}</UniqueIdentifier>
</Filter>
<Filter Include="app">
<UniqueIdentifier>{ba2fdaa9-bc69-4fb5-b789-9d2b46d7fd31}</UniqueIdentifier>
</Filter>
<Filter Include="app\spiffs">
<UniqueIdentifier>{d6547699-189a-45e8-82d8-4af0a0b4cfd7}</UniqueIdentifier>
</Filter>
<Filter Include="app\include">
<UniqueIdentifier>{131db3e8-d55b-4d0a-810b-ae33c5e41bb3}</UniqueIdentifier>
</Filter>
<Filter Include="app\platform">
<UniqueIdentifier>{184f25b5-aca7-476f-981f-16d7a8294ca7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\tools\spiffsimg\main.c">
<Filter>tools\spiffsimg</Filter>
</ClCompile>
<ClCompile Include="..\..\app\spiffs\spiffs_cache.c">
<Filter>app\spiffs</Filter>
</ClCompile>
<ClCompile Include="..\..\app\spiffs\spiffs_check.c">
<Filter>app\spiffs</Filter>
</ClCompile>
<ClCompile Include="..\..\app\spiffs\spiffs_gc.c">
<Filter>app\spiffs</Filter>
</ClCompile>
<ClCompile Include="..\..\app\spiffs\spiffs_hydrogen.c">
<Filter>app\spiffs</Filter>
</ClCompile>
<ClCompile Include="..\..\app\spiffs\spiffs_nucleus.c">
<Filter>app\spiffs</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\tools\spiffsimg\spiffs_typedefs.h">
<Filter>tools\spiffsimg</Filter>
</ClInclude>
<ClInclude Include="..\..\app\spiffs\spiffs.h">
<Filter>app\spiffs</Filter>
</ClInclude>
<ClInclude Include="..\..\app\spiffs\spiffs_nucleus.h">
<Filter>app\spiffs</Filter>
</ClInclude>
<ClInclude Include="..\..\app\spiffs\spiffs_config.h">
<Filter>app\spiffs</Filter>
</ClInclude>
<ClInclude Include="..\..\app\spiffs\nodemcu_spiffs.h">
<Filter>app\spiffs</Filter>
</ClInclude>
<ClInclude Include="..\..\app\include\user_config.h">
<Filter>app\include</Filter>
</ClInclude>
<ClInclude Include="..\..\app\platform\cpu_esp8266.h">
<Filter>app\platform</Filter>
</ClInclude>
<ClInclude Include="getopt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
#ifndef _OVERRIDE_C_TYPES_H_
#define _OVERRIDE_C_TYPES_H_
#include_next "c_types.h"
#ifndef _SDKOVERRIDES_C_TYPES_H_
#define _SDKOVERRIDES_C_TYPES_H_
typedef long long int64_t;
typedef int8_t sint8_t;
typedef int16_t sint16_t;
typedef int64_t sint64_t;
#error "Please do not use c_types.h, use <stdint.h> instead"
#endif
#ifndef _SDK_OVERRIDE_ESPCONN_H_
#define _SDK_OVERRIDE_ESPCONN_H_
// Pull in the correct lwIP header
#include "../../app/include/lwip/app/espconn.h"
#endif
#ifndef SDK_OVERRIDES_INCLUDE_ETS_SYS_H_
#define SDK_OVERRIDES_INCLUDE_ETS_SYS_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include_next "ets_sys.h"
#include "../libc/c_stdarg.h"
#include <stdarg.h>
int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
......
#ifndef _SDK_OVERRIDE_MEM_H_
#define _SDK_OVERRIDE_MEM_H_
void *pvPortMalloc (size_t sz, const char *, unsigned);
void vPortFree (void *p, const char *, unsigned);
void *pvPortZalloc (size_t sz, const char *, unsigned);
void *pvPortRealloc (void *p, size_t n, const char *, unsigned);
#include <stdlib.h>
#define MEM_DEFAULT_USE_DRAM
#include_next "mem.h"
#endif
#ifndef _SDK_OVERRIDE_OSAPI_H_
#define _SDK_OVERRIDE_OSAPI_H_
#include "rom.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#define USE_OPTIMIZE_PRINTF
#include_next "osapi.h"
int atoi(const char *nptr);
int os_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
#include "rom.h"
unsigned int uart_baudrate_detect(unsigned int uart_no, unsigned int async);
......@@ -13,6 +16,4 @@ void NmiTimSetFunc(void (*func)(void));
void call_user_start(void);
#include_next "osapi.h"
#endif
#ifndef __stdbool_h__
#define __stdbool_h__
// For compatibility with SDK. Boo.
typedef unsigned char bool;
#define BOOL bool
#define true (1)
#define false (0)
#define TRUE true
#define FALSE false
#endif
#ifndef _SDKOVERRIDES_STDINT_H_
#define _SDKOVERRIDES_STDINT_H_
#include_next "stdint.h"
// Compatibility cruft from c_types.h, ideally we should get rid of this!
typedef signed char sint8_t;
typedef signed short sint16_t;
typedef signed int sint32_t;
typedef signed long long sint64_t;
typedef unsigned long long u_int64_t;
typedef float real32_t;
typedef double real64_t;
typedef unsigned char uint8;
typedef unsigned char u8;
typedef signed char sint8;
typedef signed char int8;
typedef signed char s8;
typedef unsigned short uint16;
typedef unsigned short u16;
typedef signed short sint16;
typedef signed short s16;
typedef unsigned int uint32;
typedef unsigned int u_int;
typedef unsigned int u32;
typedef signed int sint32;
typedef signed int s32;
typedef int int32;
typedef signed long long sint64;
typedef unsigned long long uint64;
typedef unsigned long long u64;
typedef float real32;
typedef double real64;
#define __le16 u16
// And this stuff really doesn't belong in a types file in the first place...
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#define LOCAL static
typedef enum {
OK = 0,
FAIL,
PENDING,
BUSY,
CANCEL,
} STATUS;
#define BIT(nr) (1UL << (nr))
#define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b))
#define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b))
#define DMEM_ATTR __attribute__((section(".bss")))
#define SHMEM_ATTR
#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
#define STORE_ATTR __attribute__((aligned(4)))
#endif
#ifndef _OVERRIDE_STDIO_H_
#define _OVERRIDE_STDIO_H_
#include_next "stdio.h"
#ifdef __BUFSIZ__
# define BUFSIZ __BUFSIZ__
#else
# define BUFSIZ 1024
#endif
#define printf(...) do { \
unsigned char __printf_buf[BUFSIZ]; \
sprintf(__printf_buf, __VA_ARGS__); \
puts(__printf_buf); \
} while(0)
extern void output_redirect(const char *str);
#define puts output_redirect
#endif
#ifndef _OVERRIDE_STDLIB_H_
#define _OVERRIDE_STDLIB_H_
#include_next "stdlib.h"
#include <stdbool.h>
#include "mem.h"
#define free os_free
#define malloc os_malloc
#define calloc(n,sz) os_zalloc(n*sz)
#define realloc os_realloc
#endif
#ifndef SDK_OVERRIDES_INCLUDE_USER_INTERFACE_H_
#define SDK_OVERRIDES_INCLUDE_USER_INTERFACE_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include_next "user_interface.h"
bool wifi_softap_deauth(uint8 mac[6]);
......
......@@ -7,7 +7,7 @@ LUASOURCE ?= ../local/lua
FLASHSIZE ?= 4mb 32mb 8mb
FLASH_SW = -S
SUBDIRS =
APP_DIR = ../app
OBJDUMP = $(or $(shell which objdump),xtensa-lx106-elf-objdump)
#############################################################
......@@ -20,23 +20,23 @@ SPIFFSFILES ?= $(patsubst $(FSSOURCE)/%,%,$(shell find $(FSSOURCE)/ -name '*' '!
# Get the filesize of /bin/0x10000.bin and SPIFFS sizing
#
FLASH_FS_SIZE := $(shell $(CC) -E -dM - <../app/include/user_config.h | grep SPIFFS_MAX_FILESYSTEM_SIZE| cut -d ' ' -f 3)
FLASH_FS_SIZE := $(shell $(CC) -E -dM - <$(APP_DIR)/include/user_config.h | grep SPIFFS_MAX_FILESYSTEM_SIZE| cut -d ' ' -f 3)
ifneq ($(strip $(FLASH_FS_SIZE)),)
FLASHSIZE = $(shell printf "0x%x" $(FLASH_FS_SIZE))
FLASH_SW = -c
endif
FLASH_FS_LOC := $(shell $(CC) -E -dM - <../app/include/user_config.h | grep SPIFFS_FIXED_LOCATION| cut -d ' ' -f 3)
FLASH_FS_LOC := $(shell $(CC) -E -dM - <$(APP_DIR)/include/user_config.h | grep SPIFFS_FIXED_LOCATION| cut -d ' ' -f 3)
ifeq ($(strip $(FLASH_FS_LOC)),)
FLASH_FS_LOC := $(shell printf "0x%x" $$((0x$(shell $(OBJDUMP) -t ../app/.output/eagle/debug/image/eagle.app.v6.out |grep " _flash_used_end" |cut -f1 -d" ") - 0x40200000)))
FLASH_FS_LOC := $(shell printf "0x%x" $$((0x$(shell $(OBJDUMP) -t $(APP_DIR)/.output/eagle/debug/image/eagle.app.v6.out |grep " _flash_used_end" |cut -f1 -d" ") - 0x40200000)))
else
FLASH_FS_LOC := $(shell printf "0x%x" $(FLASH_FS_LOC))
endif
LFSSOURCES := $(wildcard $(LUASOURCE)/*.lua)
BUILD_TYPE := $(shell $(CC) $(EXTRA_CCFLAGS) -E -dM - <../app/include/user_config.h | grep LUA_NUMBER_INTEGRAL | wc -l)
BUILD_TYPE := $(shell $(CC) $(EXTRA_CCFLAGS) -E -dM - <$(APP_DIR)/include/user_config.h | grep LUA_NUMBER_INTEGRAL | wc -l)
ifeq ($(BUILD_TYPE),0)
LUAC_CROSS := ../luac.cross
else
......
#!/usr/bin/env python
# NB: Before sending a PR to change the above line to '#!/usr/bin/env python2', please read https://github.com/themadinventor/esptool/issues/21
#
# ESP8266 ROM Bootloader Utility
# https://github.com/themadinventor/esptool
#
# Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, other contributors as noted.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
import hashlib
import inspect
import json
import os
import serial
import struct
import subprocess
import sys
import tempfile
import time
__version__ = "1.2-dev"
class ESPROM(object):
# These are the currently known commands supported by the ROM
ESP_FLASH_BEGIN = 0x02
ESP_FLASH_DATA = 0x03
ESP_FLASH_END = 0x04
ESP_MEM_BEGIN = 0x05
ESP_MEM_END = 0x06
ESP_MEM_DATA = 0x07
ESP_SYNC = 0x08
ESP_WRITE_REG = 0x09
ESP_READ_REG = 0x0a
# Maximum block sized for RAM and Flash writes, respectively.
ESP_RAM_BLOCK = 0x1800
ESP_FLASH_BLOCK = 0x400
# Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
ESP_ROM_BAUD = 115200
# First byte of the application image
ESP_IMAGE_MAGIC = 0xe9
# Initial state for the checksum routine
ESP_CHECKSUM_MAGIC = 0xef
# OTP ROM addresses
ESP_OTP_MAC0 = 0x3ff00050
ESP_OTP_MAC1 = 0x3ff00054
ESP_OTP_MAC3 = 0x3ff0005c
# Flash sector size, minimum unit of erase.
ESP_FLASH_SECTOR = 0x1000
def __init__(self, port=0, baud=ESP_ROM_BAUD):
self._port = serial.Serial(port)
self._slip_reader = slip_reader(port)
# setting baud rate in a separate step is a workaround for
# CH341 driver on some Linux versions (this opens at 9600 then
# sets), shouldn't matter for other platforms/drivers. See
# https://github.com/themadinventor/esptool/issues/44#issuecomment-107094446
self._port.baudrate = baud
""" Read a SLIP packet from the serial port """
def read(self):
return self._slip_reader.next()
""" Write bytes to the serial port while performing SLIP escaping """
def write(self, packet):
buf = '\xc0' \
+ (packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc')) \
+ '\xc0'
self._port.write(buf)
""" Calculate checksum of a blob, as it is defined by the ROM """
@staticmethod
def checksum(data, state=ESP_CHECKSUM_MAGIC):
for b in data:
state ^= ord(b)
return state
""" Send a request and read the response """
def command(self, op=None, data=None, chk=0):
if op is not None:
pkt = struct.pack('<BBHI', 0x00, op, len(data), chk) + data
self.write(pkt)
# tries to get a response until that response has the
# same operation as the request or a retries limit has
# exceeded. This is needed for some esp8266s that
# reply with more sync responses than expected.
for retry in xrange(100):
p = self.read()
if len(p) < 8:
continue
(resp, op_ret, len_ret, val) = struct.unpack('<BBHI', p[:8])
if resp != 1:
continue
body = p[8:]
if op is None or op_ret == op:
return val, body # valid response received
raise FatalError("Response doesn't match request")
""" Perform a connection test """
def sync(self):
self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20' + 32 * '\x55')
for i in xrange(7):
self.command()
""" Try connecting repeatedly until successful, or giving up """
def connect(self):
print 'Connecting...'
for _ in xrange(4):
# issue reset-to-bootloader:
# RTS = either CH_PD or nRESET (both active low = chip in reset)
# DTR = GPIO0 (active low = boot to flasher)
self._port.setDTR(False)
self._port.setRTS(True)
time.sleep(0.05)
self._port.setDTR(True)
self._port.setRTS(False)
time.sleep(0.05)
self._port.setDTR(False)
# worst-case latency timer should be 255ms (probably <20ms)
self._port.timeout = 0.3
for _ in xrange(4):
try:
self._port.flushInput()
self._slip_reader = slip_reader(self._port)
self._port.flushOutput()
self.sync()
self._port.timeout = 5
return
except:
time.sleep(0.05)
raise FatalError('Failed to connect to ESP8266')
""" Read memory address in target """
def read_reg(self, addr):
res = self.command(ESPROM.ESP_READ_REG, struct.pack('<I', addr))
if res[1] != "\0\0":
raise FatalError('Failed to read target memory')
return res[0]
""" Write to memory address in target """
def write_reg(self, addr, value, mask, delay_us=0):
if self.command(ESPROM.ESP_WRITE_REG,
struct.pack('<IIII', addr, value, mask, delay_us))[1] != "\0\0":
raise FatalError('Failed to write target memory')
""" Start downloading an application image to RAM """
def mem_begin(self, size, blocks, blocksize, offset):
if self.command(ESPROM.ESP_MEM_BEGIN,
struct.pack('<IIII', size, blocks, blocksize, offset))[1] != "\0\0":
raise FatalError('Failed to enter RAM download mode')
""" Send a block of an image to RAM """
def mem_block(self, data, seq):
if self.command(ESPROM.ESP_MEM_DATA,
struct.pack('<IIII', len(data), seq, 0, 0) + data,
ESPROM.checksum(data))[1] != "\0\0":
raise FatalError('Failed to write to target RAM')
""" Leave download mode and run the application """
def mem_finish(self, entrypoint=0):
if self.command(ESPROM.ESP_MEM_END,
struct.pack('<II', int(entrypoint == 0), entrypoint))[1] != "\0\0":
raise FatalError('Failed to leave RAM download mode')
""" Start downloading to Flash (performs an erase) """
def flash_begin(self, size, offset):
old_tmo = self._port.timeout
num_blocks = (size + ESPROM.ESP_FLASH_BLOCK - 1) / ESPROM.ESP_FLASH_BLOCK
sectors_per_block = 16
sector_size = self.ESP_FLASH_SECTOR
num_sectors = (size + sector_size - 1) / sector_size
start_sector = offset / sector_size
head_sectors = sectors_per_block - (start_sector % sectors_per_block)
if num_sectors < head_sectors:
head_sectors = num_sectors
if num_sectors < 2 * head_sectors:
erase_size = (num_sectors + 1) / 2 * sector_size
else:
erase_size = (num_sectors - head_sectors) * sector_size
self._port.timeout = 20
t = time.time()
result = self.command(ESPROM.ESP_FLASH_BEGIN,
struct.pack('<IIII', erase_size, num_blocks, ESPROM.ESP_FLASH_BLOCK, offset))[1]
if size != 0:
print "Took %.2fs to erase flash block" % (time.time() - t)
if result != "\0\0":
raise FatalError.WithResult('Failed to enter Flash download mode (result "%s")', result)
self._port.timeout = old_tmo
""" Write block to flash """
def flash_block(self, data, seq):
result = self.command(ESPROM.ESP_FLASH_DATA,
struct.pack('<IIII', len(data), seq, 0, 0) + data,
ESPROM.checksum(data))[1]
if result != "\0\0":
raise FatalError.WithResult('Failed to write to target Flash after seq %d (got result %%s)' % seq, result)
""" Leave flash mode and run/reboot """
def flash_finish(self, reboot=False):
pkt = struct.pack('<I', int(not reboot))
if self.command(ESPROM.ESP_FLASH_END, pkt)[1] != "\0\0":
raise FatalError('Failed to leave Flash mode')
""" Run application code in flash """
def run(self, reboot=False):
# Fake flash begin immediately followed by flash end
self.flash_begin(0, 0)
self.flash_finish(reboot)
""" Read MAC from OTP ROM """
def read_mac(self):
mac0 = self.read_reg(self.ESP_OTP_MAC0)
mac1 = self.read_reg(self.ESP_OTP_MAC1)
mac3 = self.read_reg(self.ESP_OTP_MAC3)
if (mac3 != 0):
oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff)
elif ((mac1 >> 16) & 0xff) == 0:
oui = (0x18, 0xfe, 0x34)
elif ((mac1 >> 16) & 0xff) == 1:
oui = (0xac, 0xd0, 0x74)
else:
raise FatalError("Unknown OUI")
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
""" Read Chip ID from OTP ROM - see http://esp8266-re.foogod.com/wiki/System_get_chip_id_%28IoT_RTOS_SDK_0.9.9%29 """
def chip_id(self):
id0 = self.read_reg(self.ESP_OTP_MAC0)
id1 = self.read_reg(self.ESP_OTP_MAC1)
return (id0 >> 24) | ((id1 & 0xffffff) << 8)
""" Read SPI flash manufacturer and device id """
def flash_id(self):
self.flash_begin(0, 0)
self.write_reg(0x60000240, 0x0, 0xffffffff)
self.write_reg(0x60000200, 0x10000000, 0xffffffff)
flash_id = self.read_reg(0x60000240)
self.flash_finish(False)
return flash_id
""" Abuse the loader protocol to force flash to be left in write mode """
def flash_unlock_dio(self):
# Enable flash write mode
self.flash_begin(0, 0)
# Reset the chip rather than call flash_finish(), which would have
# write protected the chip again (why oh why does it do that?!)
self.mem_begin(0,0,0,0x40100000)
self.mem_finish(0x40000080)
""" Perform a chip erase of SPI flash """
def flash_erase(self):
# Trick ROM to initialize SFlash
self.flash_begin(0, 0)
# This is hacky: we don't have a custom stub, instead we trick
# the bootloader to jump to the SPIEraseChip() routine and then halt/crash
# when it tries to boot an unconfigured system.
self.mem_begin(0,0,0,0x40100000)
self.mem_finish(0x40004984)
# Yup - there's no good way to detect if we succeeded.
# It it on the other hand unlikely to fail.
def run_stub(self, stub, params, read_output=True):
stub = dict(stub)
stub['code'] = unhexify(stub['code'])
if 'data' in stub:
stub['data'] = unhexify(stub['data'])
if stub['num_params'] != len(params):
raise FatalError('Stub requires %d params, %d provided'
% (stub['num_params'], len(params)))
params = struct.pack('<' + ('I' * stub['num_params']), *params)
pc = params + stub['code']
# Upload
self.mem_begin(len(pc), 1, len(pc), stub['params_start'])
self.mem_block(pc, 0)
if 'data' in stub:
self.mem_begin(len(stub['data']), 1, len(stub['data']), stub['data_start'])
self.mem_block(stub['data'], 0)
self.mem_finish(stub['entry'])
if read_output:
print 'Stub executed, reading response:'
while True:
p = self.read()
print hexify(p)
if p == '':
return
class ESPBOOTLOADER(object):
""" These are constants related to software ESP bootloader, working with 'v2' image files """
# First byte of the "v2" application image
IMAGE_V2_MAGIC = 0xea
# First 'segment' value in a "v2" application image, appears to be a constant version value?
IMAGE_V2_SEGMENT = 4
def LoadFirmwareImage(filename):
""" Load a firmware image, without knowing what kind of file (v1 or v2) it is.
Returns a BaseFirmwareImage subclass, either ESPFirmwareImage (v1) or OTAFirmwareImage (v2).
"""
with open(filename, 'rb') as f:
magic = ord(f.read(1))
f.seek(0)
if magic == ESPROM.ESP_IMAGE_MAGIC:
return ESPFirmwareImage(f)
elif magic == ESPBOOTLOADER.IMAGE_V2_MAGIC:
return OTAFirmwareImage(f)
else:
raise FatalError("Invalid image magic number: %d" % magic)
class BaseFirmwareImage(object):
""" Base class with common firmware image functions """
def __init__(self):
self.segments = []
self.entrypoint = 0
def add_segment(self, addr, data, pad_to=4):
""" Add a segment to the image, with specified address & data
(padded to a boundary of pad_to size) """
# Data should be aligned on word boundary
l = len(data)
if l % pad_to:
data += b"\x00" * (pad_to - l % pad_to)
if l > 0:
self.segments.append((addr, len(data), data))
def load_segment(self, f, is_irom_segment=False):
""" Load the next segment from the image file """
(offset, size) = struct.unpack('<II', f.read(8))
if not is_irom_segment:
if offset > 0x40200000 or offset < 0x3ffe0000 or size > 65536:
raise FatalError('Suspicious segment 0x%x, length %d' % (offset, size))
segment_data = f.read(size)
if len(segment_data) < size:
raise FatalError('End of file reading segment 0x%x, length %d (actual length %d)' % (offset, size, len(segment_data)))
segment = (offset, size, segment_data)
self.segments.append(segment)
return segment
def save_segment(self, f, segment, checksum=None):
""" Save the next segment to the image file, return next checksum value if provided """
(offset, size, data) = segment
f.write(struct.pack('<II', offset, size))
f.write(data)
if checksum is not None:
return ESPROM.checksum(data, checksum)
def read_checksum(self, f):
""" Return ESPROM checksum from end of just-read image """
# Skip the padding. The checksum is stored in the last byte so that the
# file is a multiple of 16 bytes.
align_file_position(f, 16)
return ord(f.read(1))
def append_checksum(self, f, checksum):
""" Append ESPROM checksum to the just-written image """
align_file_position(f, 16)
f.write(struct.pack('B', checksum))
def write_v1_header(self, f, segments):
f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(segments),
self.flash_mode, self.flash_size_freq, self.entrypoint))
class ESPFirmwareImage(BaseFirmwareImage):
""" 'Version 1' firmware image, segments loaded directly by the ROM bootloader. """
def __init__(self, load_file=None):
super(ESPFirmwareImage, self).__init__()
self.flash_mode = 0
self.flash_size_freq = 0
self.version = 1
if load_file is not None:
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
# some sanity check
if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
raise FatalError('Invalid firmware image magic=%d segments=%d' % (magic, segments))
for i in xrange(segments):
self.load_segment(load_file)
self.checksum = self.read_checksum(load_file)
def save(self, filename):
with open(filename, 'wb') as f:
self.write_v1_header(f, self.segments)
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for segment in self.segments:
checksum = self.save_segment(f, segment, checksum)
self.append_checksum(f, checksum)
class OTAFirmwareImage(BaseFirmwareImage):
""" 'Version 2' firmware image, segments loaded by software bootloader stub
(ie Espressif bootloader or rboot)
"""
def __init__(self, load_file=None):
super(OTAFirmwareImage, self).__init__()
self.version = 2
if load_file is not None:
(magic, segments, first_flash_mode, first_flash_size_freq, first_entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
# some sanity check
if magic != ESPBOOTLOADER.IMAGE_V2_MAGIC:
raise FatalError('Invalid V2 image magic=%d' % (magic))
if segments != 4:
# segment count is not really segment count here, but we expect to see '4'
print 'Warning: V2 header has unexpected "segment" count %d (usually 4)' % segments
# irom segment comes before the second header
self.load_segment(load_file, True)
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
if first_flash_mode != self.flash_mode:
print('WARNING: Flash mode value in first header (0x%02x) disagrees with second (0x%02x). Using second value.'
% (first_flash_mode, self.flash_mode))
if first_flash_size_freq != self.flash_size_freq:
print('WARNING: Flash size/freq value in first header (0x%02x) disagrees with second (0x%02x). Using second value.'
% (first_flash_size_freq, self.flash_size_freq))
if first_entrypoint != self.entrypoint:
print('WARNING: Enterypoint address in first header (0x%08x) disagrees with second header (0x%08x). Using second value.'
% (first_entrypoint, self.entrypoint))
if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
raise FatalError('Invalid V2 second header magic=%d segments=%d' % (magic, segments))
# load all the usual segments
for _ in xrange(segments):
self.load_segment(load_file)
self.checksum = self.read_checksum(load_file)
def save(self, filename):
with open(filename, 'wb') as f:
# Save first header for irom0 segment
f.write(struct.pack('<BBBBI', ESPBOOTLOADER.IMAGE_V2_MAGIC, ESPBOOTLOADER.IMAGE_V2_SEGMENT,
self.flash_mode, self.flash_size_freq, self.entrypoint))
# irom0 segment identified by load address zero
irom_segments = [segment for segment in self.segments if segment[0] == 0]
if len(irom_segments) != 1:
raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments))
# save irom0 segment
irom_segment = irom_segments[0]
self.save_segment(f, irom_segment)
# second header, matches V1 header and contains loadable segments
normal_segments = [s for s in self.segments if s != irom_segment]
self.write_v1_header(f, normal_segments)
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for segment in normal_segments:
checksum = self.save_segment(f, segment, checksum)
self.append_checksum(f, checksum)
class ELFFile(object):
def __init__(self, name):
self.name = binutils_safe_path(name)
self.symbols = None
def _fetch_symbols(self):
if self.symbols is not None:
return
self.symbols = {}
try:
tool_nm = "xtensa-lx106-elf-nm"
if os.getenv('XTENSA_CORE') == 'lx106':
tool_nm = "xt-nm"
proc = subprocess.Popen([tool_nm, self.name], stdout=subprocess.PIPE)
except OSError:
print "Error calling %s, do you have Xtensa toolchain in PATH?" % tool_nm
sys.exit(1)
for l in proc.stdout:
fields = l.strip().split()
try:
if fields[0] == "U":
print "Warning: ELF binary has undefined symbol %s" % fields[1]
continue
if fields[0] == "w":
continue # can skip weak symbols
self.symbols[fields[2]] = int(fields[0], 16)
except ValueError:
raise FatalError("Failed to strip symbol output from nm: %s" % fields)
def get_symbol_addr(self, sym):
self._fetch_symbols()
return self.symbols[sym]
def get_entry_point(self):
tool_readelf = "xtensa-lx106-elf-readelf"
if os.getenv('XTENSA_CORE') == 'lx106':
tool_readelf = "xt-readelf"
try:
proc = subprocess.Popen([tool_readelf, "-h", self.name], stdout=subprocess.PIPE)
except OSError:
print "Error calling %s, do you have Xtensa toolchain in PATH?" % tool_readelf
sys.exit(1)
for l in proc.stdout:
fields = l.strip().split()
if fields[0] == "Entry":
return int(fields[3], 0)
def load_section(self, section):
tool_objcopy = "xtensa-lx106-elf-objcopy"
if os.getenv('XTENSA_CORE') == 'lx106':
tool_objcopy = "xt-objcopy"
tmpsection = binutils_safe_path(tempfile.mktemp(suffix=".section"))
try:
subprocess.check_call([tool_objcopy, "--only-section", section, "-Obinary", self.name, tmpsection])
with open(tmpsection, "rb") as f:
data = f.read()
finally:
os.remove(tmpsection)
return data
class CesantaFlasher(object):
# From stub_flasher.h
CMD_FLASH_WRITE = 1
CMD_FLASH_READ = 2
CMD_FLASH_DIGEST = 3
CMD_BOOT_FW = 6
def __init__(self, esp, baud_rate=0):
print 'Running Cesanta flasher stub...'
if baud_rate <= ESPROM.ESP_ROM_BAUD: # don't change baud rates if we already synced at that rate
baud_rate = 0
self._esp = esp
esp.run_stub(json.loads(_CESANTA_FLASHER_STUB), [baud_rate], read_output=False)
if baud_rate > 0:
esp._port.baudrate = baud_rate
# Read the greeting.
p = esp.read()
if p != 'OHAI':
raise FatalError('Failed to connect to the flasher (got %s)' % hexify(p))
def flash_write(self, addr, data, show_progress=False):
assert addr % self._esp.ESP_FLASH_SECTOR == 0, 'Address must be sector-aligned'
assert len(data) % self._esp.ESP_FLASH_SECTOR == 0, 'Length must be sector-aligned'
sys.stdout.write('Writing %d @ 0x%x... ' % (len(data), addr))
sys.stdout.flush()
self._esp.write(struct.pack('<B', self.CMD_FLASH_WRITE))
self._esp.write(struct.pack('<III', addr, len(data), 1))
num_sent, num_written = 0, 0
while num_written < len(data):
p = self._esp.read()
if len(p) == 4:
num_written = struct.unpack('<I', p)[0]
elif len(p) == 1:
status_code = struct.unpack('<B', p)[0]
raise FatalError('Write failure, status: %x' % status_code)
else:
raise FatalError('Unexpected packet while writing: %s' % hexify(p))
if show_progress:
progress = '%d (%d %%)' % (num_written, num_written * 100.0 / len(data))
sys.stdout.write(progress + '\b' * len(progress))
sys.stdout.flush()
while num_sent - num_written < 5120:
self._esp._port.write(data[num_sent:num_sent + 1024])
num_sent += 1024
p = self._esp.read()
if len(p) != 16:
raise FatalError('Expected digest, got: %s' % hexify(p))
digest = hexify(p).upper()
expected_digest = hashlib.md5(data).hexdigest().upper()
print
if digest != expected_digest:
raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest))
p = self._esp.read()
if len(p) != 1:
raise FatalError('Expected status, got: %s' % hexify(p))
status_code = struct.unpack('<B', p)[0]
if status_code != 0:
raise FatalError('Write failure, status: %x' % status_code)
def flash_read(self, addr, length, show_progress=False):
sys.stdout.write('Reading %d @ 0x%x... ' % (length, addr))
sys.stdout.flush()
self._esp.write(struct.pack('<B', self.CMD_FLASH_READ))
# USB may not be able to keep up with the read rate, especially at
# higher speeds. Since we don't have flow control, this will result in
# data loss. Hence, we use small packet size and only allow small
# number of bytes in flight, which we can reasonably expect to fit in
# the on-chip FIFO. max_in_flight = 64 works for CH340G, other chips may
# have longer FIFOs and could benefit from increasing max_in_flight.
self._esp.write(struct.pack('<IIII', addr, length, 32, 64))
data = ''
while True:
p = self._esp.read()
data += p
self._esp.write(struct.pack('<I', len(data)))
if show_progress and (len(data) % 1024 == 0 or len(data) == length):
progress = '%d (%d %%)' % (len(data), len(data) * 100.0 / length)
sys.stdout.write(progress + '\b' * len(progress))
sys.stdout.flush()
if len(data) == length:
break
if len(data) > length:
raise FatalError('Read more than expected')
p = self._esp.read()
if len(p) != 16:
raise FatalError('Expected digest, got: %s' % hexify(p))
expected_digest = hexify(p).upper()
digest = hashlib.md5(data).hexdigest().upper()
print
if digest != expected_digest:
raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest))
p = self._esp.read()
if len(p) != 1:
raise FatalError('Expected status, got: %s' % hexify(p))
status_code = struct.unpack('<B', p)[0]
if status_code != 0:
raise FatalError('Write failure, status: %x' % status_code)
return data
def flash_digest(self, addr, length, digest_block_size=0):
self._esp.write(struct.pack('<B', self.CMD_FLASH_DIGEST))
self._esp.write(struct.pack('<III', addr, length, digest_block_size))
digests = []
while True:
p = self._esp.read()
if len(p) == 16:
digests.append(p)
elif len(p) == 1:
status_code = struct.unpack('<B', p)[0]
if status_code != 0:
raise FatalError('Write failure, status: %x' % status_code)
break
else:
raise FatalError('Unexpected packet: %s' % hexify(p))
return digests[-1], digests[:-1]
def boot_fw(self):
self._esp.write(struct.pack('<B', self.CMD_BOOT_FW))
p = self._esp.read()
if len(p) != 1:
raise FatalError('Expected status, got: %s' % hexify(p))
status_code = struct.unpack('<B', p)[0]
if status_code != 0:
raise FatalError('Boot failure, status: %x' % status_code)
def slip_reader(port):
"""Generator to read SLIP packets from a serial port.
Yields one full SLIP packet at a time, raises exception on timeout or invalid data.
Designed to avoid too many calls to serial.read(1), which can bog
down on slow systems.
"""
partial_packet = None
in_escape = False
while True:
waiting = port.inWaiting()
read_bytes = port.read(1 if waiting == 0 else waiting)
if read_bytes == '':
raise FatalError("Timed out waiting for packet %s" % ("header" if partial_packet is None else "content"))
for b in read_bytes:
if partial_packet is None: # waiting for packet header
if b == '\xc0':
partial_packet = ""
else:
raise FatalError('Invalid head of packet (%r)' % b)
elif in_escape: # part-way through escape sequence
in_escape = False
if b == '\xdc':
partial_packet += '\xc0'
elif b == '\xdd':
partial_packet += '\xdb'
else:
raise FatalError('Invalid SLIP escape (%r%r)' % ('\xdb', b))
elif b == '\xdb': # start of escape sequence
in_escape = True
elif b == '\xc0': # end of packet
yield partial_packet
partial_packet = None
else: # normal byte in packet
partial_packet += b
def arg_auto_int(x):
return int(x, 0)
def div_roundup(a, b):
""" Return a/b rounded up to nearest integer,
equivalent result to int(math.ceil(float(int(a)) / float(int(b))), only
without possible floating point accuracy errors.
"""
return (int(a) + int(b) - 1) / int(b)
def binutils_safe_path(p):
"""Returns a 'safe' version of path 'p' to pass to binutils
Only does anything under Cygwin Python, where cygwin paths need to
be translated to Windows paths if the binutils wasn't compiled
using Cygwin (should also work with binutils compiled using
Cygwin, see #73.)
"""
if sys.platform == "cygwin":
try:
return subprocess.check_output(["cygpath", "-w", p]).rstrip('\n')
except subprocess.CalledProcessError:
print "WARNING: Failed to call cygpath to sanitise Cygwin path."
return p
def align_file_position(f, size):
""" Align the position in the file to the next block of specified size """
align = (size - 1) - (f.tell() % size)
f.seek(align, 1)
def hexify(s):
return ''.join('%02X' % ord(c) for c in s)
def unhexify(hs):
s = ''
for i in range(0, len(hs) - 1, 2):
s += chr(int(hs[i] + hs[i + 1], 16))
return s
class FatalError(RuntimeError):
"""
Wrapper class for runtime errors that aren't caused by internal bugs, but by
ESP8266 responses or input content.
"""
def __init__(self, message):
RuntimeError.__init__(self, message)
@staticmethod
def WithResult(message, result):
"""
Return a fatal error object that includes the hex values of
'result' as a string formatted argument.
"""
return FatalError(message % ", ".join(hex(ord(x)) for x in result))
# "Operation" commands, executable at command line. One function each
#
# Each function takes either two args (<ESPROM instance>, <args>) or a single <args>
# argument.
def load_ram(esp, args):
image = LoadFirmwareImage(args.filename)
print 'RAM boot...'
for (offset, size, data) in image.segments:
print 'Downloading %d bytes at %08x...' % (size, offset),
sys.stdout.flush()
esp.mem_begin(size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, offset)
seq = 0
while len(data) > 0:
esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq)
data = data[esp.ESP_RAM_BLOCK:]
seq += 1
print 'done!'
print 'All segments done, executing at %08x' % image.entrypoint
esp.mem_finish(image.entrypoint)
def read_mem(esp, args):
print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))
def write_mem(esp, args):
esp.write_reg(args.address, args.value, args.mask, 0)
print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)
def dump_mem(esp, args):
f = file(args.filename, 'wb')
for i in xrange(args.size / 4):
d = esp.read_reg(args.address + (i * 4))
f.write(struct.pack('<I', d))
if f.tell() % 1024 == 0:
print '\r%d bytes read... (%d %%)' % (f.tell(),
f.tell() * 100 / args.size),
sys.stdout.flush()
print 'Done!'
def write_flash(esp, args):
flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40, '16m-c1': 0x50, '32m-c1':0x60, '32m-c2':0x70, '64m':0x80, '128m':0x90}[args.flash_size]
flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
flash_params = struct.pack('BB', flash_mode, flash_size_freq)
flasher = CesantaFlasher(esp, args.baud)
for address, argfile in args.addr_filename:
image = argfile.read()
argfile.seek(0) # rewind in case we need it again
# Fix sflash config data.
if address == 0 and image[0] == '\xe9':
print 'Flash params set to 0x%02x%02x' % (flash_mode, flash_size_freq)
image = image[0:2] + flash_params + image[4:]
# Pad to sector size, which is the minimum unit of writing (erasing really).
if len(image) % esp.ESP_FLASH_SECTOR != 0:
image += '\xff' * (esp.ESP_FLASH_SECTOR - (len(image) % esp.ESP_FLASH_SECTOR))
t = time.time()
flasher.flash_write(address, image, not args.no_progress)
t = time.time() - t
print ('\rWrote %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...'
% (len(image), address, t, len(image) / t * 8 / 1000))
print 'Leaving...'
if args.verify:
print 'Verifying just-written flash...'
_verify_flash(flasher, args, flash_params)
flasher.boot_fw()
def image_info(args):
image = LoadFirmwareImage(args.filename)
print('Image version: %d' % image.version)
print('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set'
print '%d segments' % len(image.segments)
print
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for (idx, (offset, size, data)) in enumerate(image.segments):
if image.version == 2 and idx == 0:
print 'Segment 1: %d bytes IROM0 (no load address)' % size
else:
print 'Segment %d: %5d bytes at %08x' % (idx + 1, size, offset)
checksum = ESPROM.checksum(data, checksum)
print
print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')
def make_image(args):
image = ESPFirmwareImage()
if len(args.segfile) == 0:
raise FatalError('No segments specified')
if len(args.segfile) != len(args.segaddr):
raise FatalError('Number of specified files does not match number of specified addresses')
for (seg, addr) in zip(args.segfile, args.segaddr):
data = file(seg, 'rb').read()
image.add_segment(addr, data)
image.entrypoint = args.entrypoint
image.save(args.output)
def elf2image(args):
e = ELFFile(args.input)
if args.version == '1':
image = ESPFirmwareImage()
else:
image = OTAFirmwareImage()
irom_data = e.load_section('.irom0.text')
if len(irom_data) == 0:
raise FatalError(".irom0.text section not found in ELF file - can't create V2 image.")
image.add_segment(0, irom_data, 16)
image.entrypoint = e.get_entry_point()
for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
data = e.load_section(section)
image.add_segment(e.get_symbol_addr(start), data)
image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40, '16m-c1': 0x50, '32m-c1':0x60, '32m-c2':0x70, '64m':0x80, '128m':0x90}[args.flash_size]
image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
irom_offs = e.get_symbol_addr("_irom0_text_start") - 0x40200000
if args.version == '1':
if args.output is None:
args.output = args.input + '-'
image.save(args.output + "0x00000.bin")
data = e.load_section(".irom0.text")
if irom_offs < 0:
raise FatalError('Address of symbol _irom0_text_start in ELF is located before flash mapping address. Bad linker script?')
if (irom_offs & 0xFFF) != 0: # irom0 isn't flash sector aligned
print "WARNING: irom0 section offset is 0x%08x. ELF is probably linked for 'elf2image --version=2'" % irom_offs
with open(args.output + "0x%05x.bin" % irom_offs, "wb") as f:
f.write(data)
f.close()
else: # V2 OTA image
if args.output is None:
args.output = "%s-0x%05x.bin" % (os.path.splitext(args.input)[0], irom_offs & ~(ESPROM.ESP_FLASH_SECTOR - 1))
image.save(args.output)
def read_mac(esp, args):
mac = esp.read_mac()
print 'MAC: %s' % ':'.join(map(lambda x: '%02x' % x, mac))
def chip_id(esp, args):
chipid = esp.chip_id()
print 'Chip ID: 0x%08x' % chipid
def erase_flash(esp, args):
print 'Erasing flash (this may take a while)...'
esp.flash_erase()
def run(esp, args):
esp.run()
def flash_id(esp, args):
flash_id = esp.flash_id()
print 'Manufacturer: %02x' % (flash_id & 0xff)
print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)
def read_flash(esp, args):
flasher = CesantaFlasher(esp, args.baud)
t = time.time()
data = flasher.flash_read(args.address, args.size, not args.no_progress)
t = time.time() - t
print ('\rRead %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...'
% (len(data), args.address, t, len(data) / t * 8 / 1000))
file(args.filename, 'wb').write(data)
def _verify_flash(flasher, args, flash_params=None):
differences = False
for address, argfile in args.addr_filename:
image = argfile.read()
argfile.seek(0) # rewind in case we need it again
if address == 0 and image[0] == '\xe9' and flash_params is not None:
image = image[0:2] + flash_params + image[4:]
image_size = len(image)
print 'Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size, image_size, address, argfile.name)
# Try digest first, only read if there are differences.
digest, _ = flasher.flash_digest(address, image_size)
digest = hexify(digest).upper()
expected_digest = hashlib.md5(image).hexdigest().upper()
if digest == expected_digest:
print '-- verify OK (digest matched)'
continue
else:
differences = True
if getattr(args, 'diff', 'no') != 'yes':
print '-- verify FAILED (digest mismatch)'
continue
flash = flasher.flash_read(address, image_size)
assert flash != image
diff = [i for i in xrange(image_size) if flash[i] != image[i]]
print '-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff), address + diff[0])
for d in diff:
print ' %08x %02x %02x' % (address + d, ord(flash[d]), ord(image[d]))
if differences:
raise FatalError("Verify failed.")
def verify_flash(esp, args, flash_params=None):
flasher = CesantaFlasher(esp)
_verify_flash(flasher, args, flash_params)
def version(args):
print __version__
#
# End of operations functions
#
def main():
parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool')
parser.add_argument(
'--port', '-p',
help='Serial port device',
default=os.environ.get('ESPTOOL_PORT', '/dev/ttyUSB0'))
parser.add_argument(
'--baud', '-b',
help='Serial port baud rate used when flashing/reading',
type=arg_auto_int,
default=os.environ.get('ESPTOOL_BAUD', ESPROM.ESP_ROM_BAUD))
subparsers = parser.add_subparsers(
dest='operation',
help='Run esptool {command} -h for additional help')
parser_load_ram = subparsers.add_parser(
'load_ram',
help='Download an image to RAM and execute')
parser_load_ram.add_argument('filename', help='Firmware image')
parser_dump_mem = subparsers.add_parser(
'dump_mem',
help='Dump arbitrary memory to disk')
parser_dump_mem.add_argument('address', help='Base address', type=arg_auto_int)
parser_dump_mem.add_argument('size', help='Size of region to dump', type=arg_auto_int)
parser_dump_mem.add_argument('filename', help='Name of binary dump')
parser_read_mem = subparsers.add_parser(
'read_mem',
help='Read arbitrary memory location')
parser_read_mem.add_argument('address', help='Address to read', type=arg_auto_int)
parser_write_mem = subparsers.add_parser(
'write_mem',
help='Read-modify-write to arbitrary memory location')
parser_write_mem.add_argument('address', help='Address to write', type=arg_auto_int)
parser_write_mem.add_argument('value', help='Value', type=arg_auto_int)
parser_write_mem.add_argument('mask', help='Mask of bits to write', type=arg_auto_int)
def add_spi_flash_subparsers(parent):
""" Add common parser arguments for SPI flash properties """
parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency',
choices=['40m', '26m', '20m', '80m'],
default=os.environ.get('ESPTOOL_FF', '40m'))
parent.add_argument('--flash_mode', '-fm', help='SPI Flash mode',
choices=['qio', 'qout', 'dio', 'dout'],
default=os.environ.get('ESPTOOL_FM', 'qio'))
parent.add_argument('--flash_size', '-fs', help='SPI Flash size in Mbit', type=str.lower,
choices=['4m', '2m', '8m', '16m', '32m', '16m-c1', '32m-c1', '32m-c2', '64m', '128m'],
default=os.environ.get('ESPTOOL_FS', '4m'))
parser_write_flash = subparsers.add_parser(
'write_flash',
help='Write a binary blob to flash')
parser_write_flash.add_argument('addr_filename', metavar='<address> <filename>', help='Address followed by binary filename, separated by space',
action=AddrFilenamePairAction)
add_spi_flash_subparsers(parser_write_flash)
parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true")
parser_write_flash.add_argument('--verify', help='Verify just-written data (only necessary if very cautious, data is already CRCed', action='store_true')
subparsers.add_parser(
'run',
help='Run application code in flash')
parser_image_info = subparsers.add_parser(
'image_info',
help='Dump headers from an application image')
parser_image_info.add_argument('filename', help='Image file to parse')
parser_make_image = subparsers.add_parser(
'make_image',
help='Create an application image from binary files')
parser_make_image.add_argument('output', help='Output image file')
parser_make_image.add_argument('--segfile', '-f', action='append', help='Segment input file')
parser_make_image.add_argument('--segaddr', '-a', action='append', help='Segment base address', type=arg_auto_int)
parser_make_image.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int, default=0)
parser_elf2image = subparsers.add_parser(
'elf2image',
help='Create an application image from ELF file')
parser_elf2image.add_argument('input', help='Input ELF file')
parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str)
parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2'], default='1')
add_spi_flash_subparsers(parser_elf2image)
subparsers.add_parser(
'read_mac',
help='Read MAC address from OTP ROM')
subparsers.add_parser(
'chip_id',
help='Read Chip ID from OTP ROM')
subparsers.add_parser(
'flash_id',
help='Read SPI flash manufacturer and device ID')
parser_read_flash = subparsers.add_parser(
'read_flash',
help='Read SPI flash content')
parser_read_flash.add_argument('address', help='Start address', type=arg_auto_int)
parser_read_flash.add_argument('size', help='Size of region to dump', type=arg_auto_int)
parser_read_flash.add_argument('filename', help='Name of binary dump')
parser_read_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true")
parser_verify_flash = subparsers.add_parser(
'verify_flash',
help='Verify a binary blob against flash')
parser_verify_flash.add_argument('addr_filename', help='Address and binary file to verify there, separated by space',
action=AddrFilenamePairAction)
parser_verify_flash.add_argument('--diff', '-d', help='Show differences',
choices=['no', 'yes'], default='no')
subparsers.add_parser(
'erase_flash',
help='Perform Chip Erase on SPI flash')
subparsers.add_parser(
'version', help='Print esptool version')
# internal sanity check - every operation matches a module function of the same name
for operation in subparsers.choices.keys():
assert operation in globals(), "%s should be a module function" % operation
args = parser.parse_args()
print 'esptool.py v%s' % __version__
# operation function can take 1 arg (args), 2 args (esp, arg)
# or be a member function of the ESPROM class.
operation_func = globals()[args.operation]
operation_args,_,_,_ = inspect.getargspec(operation_func)
if operation_args[0] == 'esp': # operation function takes an ESPROM connection object
initial_baud = min(ESPROM.ESP_ROM_BAUD, args.baud) # don't sync faster than the default baud rate
esp = ESPROM(args.port, initial_baud)
esp.connect()
operation_func(esp, args)
else:
operation_func(args)
class AddrFilenamePairAction(argparse.Action):
""" Custom parser class for the address/filename pairs passed as arguments """
def __init__(self, option_strings, dest, nargs='+', **kwargs):
super(AddrFilenamePairAction, self).__init__(option_strings, dest, nargs, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
# validate pair arguments
pairs = []
for i in range(0,len(values),2):
try:
address = int(values[i],0)
except ValueError as e:
raise argparse.ArgumentError(self,'Address "%s" must be a number' % values[i])
try:
argfile = open(values[i + 1], 'rb')
except IOError as e:
raise argparse.ArgumentError(self, e)
except IndexError:
raise argparse.ArgumentError(self,'Must be pairs of an address and the binary filename to write there')
pairs.append((address, argfile))
setattr(namespace, self.dest, pairs)
# This is "wrapped" stub_flasher.c, to be loaded using run_stub.
_CESANTA_FLASHER_STUB = """\
{"code_start": 1074790404, "code": "080000601C000060000000601000006031FCFF71FCFF\
81FCFFC02000680332D218C020004807404074DCC48608005823C0200098081BA5A9239245005803\
1B555903582337350129230B446604DFC6F3FF21EEFFC0200069020DF0000000010078480040004A\
0040B449004012C1F0C921D911E901DD0209312020B4ED033C2C56C2073020B43C3C56420701F5FF\
C000003C4C569206CD0EEADD860300202C4101F1FFC0000056A204C2DCF0C02DC0CC6CCAE2D1EAFF\
0606002030F456D3FD86FBFF00002020F501E8FFC00000EC82D0CCC0C02EC0C73DEB2ADC46030020\
2C4101E1FFC00000DC42C2DCF0C02DC056BCFEC602003C5C8601003C6C4600003C7C08312D0CD811\
C821E80112C1100DF0000C180000140010400C0000607418000064180000801800008C1800008418\
0000881800009018000018980040880F0040A80F0040349800404C4A0040740F0040800F0040980F\
00400099004012C1E091F5FFC961CD0221EFFFE941F9310971D9519011C01A223902E2D1180C0222\
6E1D21E4FF31E9FF2AF11A332D0F42630001EAFFC00000C030B43C2256A31621E1FF1A2228022030\
B43C3256B31501ADFFC00000DD023C4256ED1431D6FF4D010C52D90E192E126E0101DDFFC0000021\
D2FF32A101C020004802303420C0200039022C0201D7FFC00000463300000031CDFF1A333803D023\
C03199FF27B31ADC7F31CBFF1A3328030198FFC0000056C20E2193FF2ADD060E000031C6FF1A3328\
030191FFC0000056820DD2DD10460800000021BEFF1A2228029CE231BCFFC020F51A33290331BBFF\
C02C411A332903C0F0F4222E1D22D204273D9332A3FFC02000280E27B3F721ABFF381E1A2242A400\
01B5FFC00000381E2D0C42A40001B3FFC0000056120801B2FFC00000C02000280EC2DC0422D2FCC0\
2000290E01ADFFC00000222E1D22D204226E1D281E22D204E7B204291E860000126E012198FF32A0\
042A21C54C003198FF222E1D1A33380337B202C6D6FF2C02019FFFC000002191FF318CFF1A223A31\
019CFFC00000218DFF1C031A22C549000C02060300003C528601003C624600003C72918BFF9A1108\
71C861D851E841F83112C1200DF00010000068100000581000007010000074100000781000007C10\
0000801000001C4B0040803C004091FDFF12C1E061F7FFC961E941F9310971D9519011C01A662906\
21F3FFC2D1101A22390231F2FF0C0F1A33590331EAFFF26C1AED045C2247B3028636002D0C016DFF\
C0000021E5FF41EAFF2A611A4469040622000021E4FF1A222802F0D2C0D7BE01DD0E31E0FF4D0D1A\
3328033D0101E2FFC00000561209D03D2010212001DFFFC000004D0D2D0C3D01015DFFC0000041D5\
FFDAFF1A444804D0648041D2FF1A4462640061D1FF106680622600673F1331D0FF10338028030C43\
853A002642164613000041CAFF222C1A1A444804202FC047328006F6FF222C1A273F3861C2FF222C\
1A1A6668066732B921BDFF3D0C1022800148FFC0000021BAFF1C031A2201BFFFC000000C02460300\
5C3206020000005C424600005C5291B7FF9A110871C861D851E841F83112C1200DF0B0100000C010\
0000D010000012C1E091FEFFC961D951E9410971F931CD039011C0ED02DD0431A1FF9C1422A06247\
B302062D0021F4FF1A22490286010021F1FF1A223902219CFF2AF12D0F011FFFC00000461C0022D1\
10011CFFC0000021E9FFFD0C1A222802C7B20621E6FF1A22F8022D0E3D014D0F0195FFC000008C52\
22A063C6180000218BFF3D01102280F04F200111FFC00000AC7D22D1103D014D0F010DFFC0000021\
D6FF32D110102280010EFFC0000021D3FF1C031A220185FFC00000FAEEF0CCC056ACF821CDFF317A\
FF1A223A310105FFC0000021C9FF1C031A22017CFFC000002D0C91C8FF9A110871C861D851E841F8\
3112C1200DF0000200600000001040020060FFFFFF0012C1E00C02290131FAFF21FAFF026107C961\
C02000226300C02000C80320CC10564CFF21F5FFC02000380221F4FF20231029010C432D010163FF\
C0000008712D0CC86112C1200DF00080FE3F8449004012C1D0C9A109B17CFC22C1110C13C51C0026\
1202463000220111C24110B68202462B0031F5FF3022A02802A002002D011C03851A0066820A2801\
32210105A6FF0607003C12C60500000010212032A01085180066A20F2221003811482105B3FF2241\
10861A004C1206FDFF2D011C03C5160066B20E280138114821583185CFFF06F7FF005C1286F5FF00\
10212032A01085140066A20D2221003811482105E1FF06EFFF0022A06146EDFF45F0FFC6EBFF0000\
01D2FFC0000006E9FF000C022241100C1322C110C50F00220111060600000022C1100C13C50E0022\
011132C2FA303074B6230206C8FF08B1C8A112C1300DF0000000000010404F484149007519031027\
000000110040A8100040BC0F0040583F0040CC2E00401CE20040D83900408000004021F4FF12C1E0\
C961C80221F2FF097129010C02D951C91101F4FFC0000001F3FFC00000AC2C22A3E801F2FFC00000\
21EAFFC031412A233D0C01EFFFC000003D0222A00001EDFFC00000C1E4FF2D0C01E8FFC000002D01\
32A004450400C5E7FFDD022D0C01E3FFC00000666D1F4B2131DCFF4600004B22C0200048023794F5\
31D9FFC0200039023DF08601000001DCFFC000000871C861D85112C1200DF000000012C1F0026103\
01EAFEC00000083112C1100DF000643B004012C1D0E98109B1C9A1D991F97129013911E2A0C001FA\
FFC00000CD02E792F40C0DE2A0C0F2A0DB860D00000001F4FFC00000204220E71240F7921C226102\
01EFFFC0000052A0DC482157120952A0DD571205460500004D0C3801DA234242001BDD3811379DC5\
C6000000000C0DC2A0C001E3FFC00000C792F608B12D0DC8A1D891E881F87112C1300DF00000", "\
entry": 1074792180, "num_params": 1, "params_start": 1074790400, "data": "FE0510\
401A0610403B0610405A0610407A061040820610408C0610408C061040", "data_start": 10736\
43520}
"""
if __name__ == '__main__':
try:
main()
except FatalError as e:
print '\nA fatal error occurred: %s' % e
sys.exit(2)
local empty = { }
local read_write = {read_only = false}
stds.nodemcu_libs = {
read_globals = {
adc = {
fields = {
INIT_ADC = empty,
INIT_VDD33 = empty,
force_init_mode = empty,
read = empty,
readvdd33 = empty
}
},
ads1115 = {
fields = {
ADDR_GND = empty,
ADDR_SCL = empty,
ADDR_SDA = empty,
ADDR_VDD = empty,
CMODE_TRAD = empty,
CMODE_WINDOW = empty,
COMP_1CONV = empty,
COMP_2CONV = empty,
COMP_4CONV = empty,
CONTINUOUS = empty,
CONV_RDY_1 = empty,
CONV_RDY_2 = empty,
CONV_RDY_4 = empty,
DIFF_0_1 = empty,
DIFF_0_3 = empty,
DIFF_1_3 = empty,
DIFF_2_3 = empty,
DR_128SPS = empty,
DR_1600SPS = empty,
DR_16SPS = empty,
DR_2400SPS = empty,
DR_250SPS = empty,
DR_32SPS = empty,
DR_3300SPS = empty,
DR_475SPS = empty,
DR_490SPS = empty,
DR_64SPS = empty,
DR_860SPS = empty,
DR_8SPS = empty,
DR_920SPS = empty,
GAIN_0_256V = empty,
GAIN_0_512V = empty,
GAIN_1_024V = empty,
GAIN_2_048V = empty,
GAIN_4_096V = empty,
GAIN_6_144V = empty,
SINGLE_0 = empty,
SINGLE_1 = empty,
SINGLE_2 = empty,
SINGLE_3 = empty,
SINGLE_SHOT = empty,
ads1015 = empty,
ads1115 = empty,
read = empty,
reset = empty,
}
},
adxl345 = {
fields = {
read = empty,
setup = empty
}
},
am2320 = {
fields = {
read = empty,
setup = empty
}
},
apa102 = {
fields = {
write = empty
}
},
bit = {
fields = {
arshift = empty,
band = empty,
bit = empty,
bnot = empty,
bor = empty,
bxor = empty,
clear = empty,
isclear = empty,
isset = empty,
lshift = empty,
rshift = empty,
set = empty
}
},
bloom = {
fields = {
create = empty
}
},
bme280 = {
fields = {
altitude = empty,
baro = empty,
dewpoint = empty,
humi = empty,
qfe2qnh = empty,
read = empty,
setup = empty,
startreadout = empty,
temp = empty
}
},
bme680 = {
fields = {
altitude = empty,
dewpoint = empty,
qfe2qnh = empty,
read = empty,
setup = empty,
startreadout = empty
}
},
bmp085 = {
fields = {
pressure = empty,
pressure_raw = empty,
setup = empty,
temperature = empty
}
},
coap = {
fields = {
CON = empty,
Client = empty,
EXI = empty,
JSON = empty,
LINKFORMAT = empty,
NON = empty,
OCTET_STREAM = empty,
Server = empty,
TEXT_PLAIN = empty,
XML = empty
}
},
color_utils = {
fields = {
colorWheel = empty,
grb2hsv = empty,
hsv2grb = empty,
hsv2grbw = empty
}
},
cron = {
fields = {
reset = empty,
schedule = empty
}
},
crypto = {
fields = {
decrypt = empty,
encrypt = empty,
fhash = empty,
hash = empty,
hmac = empty,
mask = empty,
new_hash = empty,
new_hmac = empty,
sha1 = empty,
toBase64 = empty,
toHex = empty
}
},
dht = {
fields = {
ERROR_CHECKSUM = empty,
ERROR_TIMEOUT = empty,
OK = empty,
read = empty,
read11 = empty,
readxx = empty
}
},
encoder = {
fields = {
fromBase64 = empty,
fromHex = empty,
toBase64 = empty,
toHex = empty
}
},
enduser_setup = {
fields = {
manual = empty,
start = empty,
stop = empty
}
},
file = {
fields = {
close = empty,
exists = empty,
flush = empty,
fsinfo = empty,
getcontents = empty,
list = empty,
on = empty,
open = empty,
putcontents = empty,
read = empty,
readline = empty,
remove = empty,
rename = empty,
seek = empty,
stat = empty,
write = empty,
writeline = empty
}
},
gdbstub = {
fields = {
brk = empty,
gdboutput = empty,
open = empty
}
},
gpio = {
fields = {
FLOAT = empty,
HIGH = empty,
INPUT = empty,
INT = empty,
LOW = empty,
OPENDRAIN = empty,
OUTPUT = empty,
PULLUP = empty,
mode = empty,
read = empty,
serout = empty,
trig = empty,
write = empty,
pulse = {
fields = {
adjust = empty,
cancel = empty,
getstate = empty,
start = empty,
stop = empty,
update = empty
}
}
}
},
hdc1080 = {
fields = {
read = empty,
setup = empty
}
},
hmc5883 = {
fields = {
read = empty,
setup = empty
}
},
http = {
fields = {
ERROR = empty,
OK = empty,
delete = empty,
get = empty,
post = empty,
put = empty,
request = empty
}
},
hx711 = {
fields = {
init = empty,
read = empty
}
},
i2c = {
fields = {
FAST = empty,
FASTPLUS = empty,
RECEIVER = empty,
SLOW = empty,
TRANSMITTER = empty,
address = empty,
read = empty,
setup = empty,
start = empty,
stop = empty,
write = empty
}
},
l3g4200d = {
fields = {
read = empty,
setup = empty
}
},
mcp4725 = {
fields = {
PWRDN_100K = empty,
PWRDN_1K = empty,
PWRDN_500K = empty,
PWRDN_NONE = empty,
read = empty,
write = empty
}
},
mdns = {
fields = {
close = empty,
register = empty
}
},
mqtt = {
fields = {
CONNACK_ACCEPTED = empty,
CONNACK_REFUSED_BAD_USER_OR_PASS = empty,
CONNACK_REFUSED_ID_REJECTED = empty,
CONNACK_REFUSED_NOT_AUTHORIZED = empty,
CONNACK_REFUSED_PROTOCOL_VER = empty,
CONNACK_REFUSED_SERVER_UNAVAILABLE = empty,
CONN_FAIL_DNS = empty,
CONN_FAIL_NOT_A_CONNACK_MSG = empty,
CONN_FAIL_SERVER_NOT_FOUND = empty,
CONN_FAIL_TIMEOUT_RECEIVING = empty,
CONN_FAIL_TIMEOUT_SENDING = empty,
Client = empty
}
},
net = {
fields = {
TCP = empty,
UDP = empty,
cert = empty,
createConnection = empty,
createServer = empty,
createUDPSocket = empty,
dns = {
fields = {
getdnsserver = empty,
resolve = empty,
setdnsserver = empty
}
},
multicastJoin = empty,
multicastLeave = empty
}
},
node = {
fields = {
CPU160MHZ = empty,
CPU80MHZ = empty,
bootreason = empty,
chipid = empty,
compile = empty,
dsleep = empty,
dsleepMax = empty,
dsleepsetoption = empty,
flashid = empty,
flashindex = empty,
flashreload = empty,
flashsize = empty,
getcpufreq = empty,
getpartitiontable = empty,
heap = empty,
info = empty,
input = empty,
osprint = empty,
output = empty,
random = empty,
readrcr = empty,
readvdd33 = empty,
restart = empty,
restore = empty,
setcpufreq = empty,
setpartitiontable = empty,
sleep = empty,
stripdebug = empty,
writercr = empty,
egc = {
fields = {
setmode = empty,
meminfo = empty
}
},
task = {
fields = {
post = empty
}
}
}
},
ow = {
fields = {
check_crc16 = empty,
crc16 = empty,
crc8 = empty,
depower = empty,
read = empty,
read_bytes = empty,
reset = empty,
reset_search = empty,
search = empty,
select = empty,
setup = empty,
skip = empty,
target_search = empty,
write = empty,
write_bytes = empty
}
},
pcm = {
fields = {
RATE_10K = empty,
RATE_12K = empty,
RATE_16K = empty,
RATE_1K = empty,
RATE_2K = empty,
RATE_4K = empty,
RATE_5K = empty,
RATE_8K = empty,
SD = empty,
new = empty
}
},
pwm = {
fields = {
close = empty,
getclock = empty,
getduty = empty,
setclock = empty,
setduty = empty,
setup = empty,
start = empty,
stop = empty
}
},
pwm2 = {
fields = {
get_pin_data = empty,
get_timer_data = empty,
release_pin = empty,
set_duty = empty,
setup_pin_hz = empty,
setup_pin_sec = empty,
start = empty,
stop = empty,
}
},
rc = {
fields = {
send = empty
}
},
rfswitch = {
fields = {
send = empty
}
},
rotary = {
fields = {
ALL = empty,
CLICK = empty,
DBLCLICK = empty,
LONGPRESS = empty,
PRESS = empty,
RELEASE = empty,
TURN = empty,
close = empty,
getpos = empty,
on = empty,
setup = empty
}
},
rtcfifo = {
fields = {
count = empty,
drop = empty,
dsleep_until_sample = empty,
peek = empty,
pop = empty,
prepare = empty,
put = empty,
ready = empty
}
},
rtcmem = {
fields = {
read32 = empty,
write32 = empty
}
},
rtctime = {
fields = {
adjust_delta = empty,
dsleep = empty,
dsleep_aligned = empty,
epoch2cal = empty,
get = empty,
set = empty
}
},
si7021 = {
fields = {
HEATER_DISABLE = empty,
HEATER_ENABLE = empty,
RH08_TEMP12 = empty,
RH10_TEMP13 = empty,
RH11_TEMP11 = empty,
RH12_TEMP14 = empty,
firmware = empty,
read = empty,
serial = empty,
setting = empty,
setup = empty
}
},
sigma_delta = {
fields = {
close = empty,
setprescale = empty,
setpwmduty = empty,
settarget = empty,
setup = empty
}
},
sjson = {
fields = {
decode = empty,
decoder = empty,
encode = empty,
encoder = empty
}
},
sntp = {
fields = {
getoffset = empty,
setoffset = empty,
sync = empty
}
},
somfy = {
fields = {
DOWN = empty,
PROG = empty,
STOP = empty,
UP = empty,
sendcommand = empty
}
},
spi = {
fields = {
CPHA_HIGH = empty,
CPHA_LOW = empty,
CPOL_HIGH = empty,
CPOL_LOW = empty,
DATABITS_8 = empty,
FULLDUPLEX = empty,
HALFDUPLEX = empty,
MASTER = empty,
SLAVE = empty,
get_miso = empty,
recv = empty,
send = empty,
set_clock_div = empty,
set_mosi = empty,
setup = empty,
transaction = empty
}
},
switec = {
fields = {
close = empty,
dequeue = empty,
getpos = empty,
moveto = empty,
reset = empty,
setup = empty
}
},
tcs34725 = {
fields = {
disable = empty,
enable = empty,
raw = empty,
setGain = empty,
setIntegrationTime = empty,
setup = empty
}
},
tls = {
fields = {
createConnection = empty,
setDebug = empty,
cert = {
fields = {
auth = empty,
verify = empty
}
}
}
},
tm1829 = {
fields = {
write = empty
}
},
tmr = {
fields = {
ALARM_AUTO = empty,
ALARM_SEMI = empty,
ALARM_SINGLE = empty,
create = empty,
delay = empty,
now = empty,
resume_all = empty,
softwd = empty,
suspend_all = empty,
time = empty,
wdclr = empty
}
},
tsl2561 = {
fields = {
ADDRESS_FLOAT = empty,
ADDRESS_GND = empty,
ADDRESS_VDD = empty,
GAIN_16X = empty,
GAIN_1X = empty,
INTEGRATIONTIME_101MS = empty,
INTEGRATIONTIME_13MS = empty,
INTEGRATIONTIME_402MS = empty,
PACKAGE_CS = empty,
PACKAGE_T_FN_CL = empty,
TSL2561_ERROR_I2CBUSY = empty,
TSL2561_ERROR_I2CINIT = empty,
TSL2561_ERROR_LAST = empty,
TSL2561_ERROR_NOINIT = empty,
TSL2561_OK = empty,
getlux = empty,
getrawchannels = empty,
init = empty,
settiming = empty
}
},
-- There would be too many fields for all the fonts and displays
u8g2 = {other_fields = true},
uart = {
fields = {
PARITY_EVEN = empty,
PARITY_NONE = empty,
PARITY_ODD = empty,
STOPBITS_1 = empty,
STOPBITS_1_5 = empty,
STOPBITS_2 = empty,
alt = empty,
getconfig = empty,
on = empty,
setup = empty,
write = empty
}
},
-- There would be too many fields for all the fonts and displays
ucg = {other_fields = true},
websocket = {
fields = {
createClient = empty
}
},
wifi = {
fields = {
COUNTRY_AUTO = empty,
COUNTRY_MANUAL = empty,
LIGHT_SLEEP = empty,
MODEM_SLEEP = empty,
NONE_SLEEP = empty,
NULLMODE = empty,
OPEN = empty,
PHYMODE_B = empty,
PHYMODE_G = empty,
PHYMODE_N = empty,
SOFTAP = empty,
STATION = empty,
STATIONAP = empty,
STA_APNOTFOUND = empty,
STA_CONNECTING = empty,
STA_FAIL = empty,
STA_GOTIP = empty,
STA_IDLE = empty,
STA_WRONGPWD = empty,
WEP = empty,
WPA2_PSK = empty,
WPA_PSK = empty,
WPA_WPA2_PSK = empty,
getchannel = empty,
getcountry = empty,
getdefaultmode = empty,
getmode = empty,
getphymode = empty,
nullmodesleep = empty,
resume = empty,
setcountry = empty,
setmaxtxpower = empty,
setmode = empty,
setphymode = empty,
sleeptype = empty,
startsmart = empty,
stopsmart = empty,
suspend = empty,
sta = {
fields = {
autoconnect = empty,
changeap = empty,
clearconfig = empty,
config = empty,
connect = empty,
disconnect = empty,
getap = empty,
getapindex = empty,
getapinfo = empty,
getbroadcast = empty,
getconfig = empty,
getdefaultconfig = empty,
gethostname = empty,
getip = empty,
getmac = empty,
getrssi = empty,
setaplimit = empty,
sethostname = empty,
setip = empty,
setmac = empty,
sleeptype = empty,
status = empty
}
},
ap = {
fields = {
config = empty,
deauth = empty,
getbroadcast = empty,
getclient = empty,
getconfig = empty,
getdefaultconfig = empty,
getip = empty,
getmac = empty,
setip = empty,
setmac = empty,
dhcp = {
fields = {
config = empty,
start = empty,
stop = empty
}
},
}
},
eventmon = {
fields = {
AP_PROBEREQRECVED = empty,
AP_STACONNECTED = empty,
AP_STADISCONNECTED = empty,
EVENT_MAX = empty,
STA_AUTHMODE_CHANGE = empty,
STA_CONNECTED = empty,
STA_DHCP_TIMEOUT = empty,
STA_DISCONNECTED = empty,
STA_GOT_IP = empty,
WIFI_MODE_CHANGED = empty,
register = empty,
unregister = empty,
reason = {
fields = {
["4WAY_HANDSHAKE_TIMEOUT"] = empty,
["802_1X_AUTH_FAILED"] = empty,
AKMP_INVALID = empty,
ASSOC_EXPIRE = empty,
ASSOC_FAIL = empty,
ASSOC_LEAVE = empty,
ASSOC_NOT_AUTHED = empty,
ASSOC_TOOMANY = empty,
AUTH_EXPIRE = empty,
AUTH_FAIL = empty,
AUTH_LEAVE = empty,
BEACON_TIMEOUT = empty,
CIPHER_SUITE_REJECTED = empty,
DISASSOC_PWRCAP_BAD = empty,
DISASSOC_SUPCHAN_BAD = empty,
GROUP_CIPHER_INVALID = empty,
GROUP_KEY_UPDATE_TIMEOUT = empty,
HANDSHAKE_TIMEOUT = empty,
IE_INVALID = empty,
IE_IN_4WAY_DIFFERS = empty,
INVALID_RSN_IE_CAP = empty,
MIC_FAILURE = empty,
NOT_ASSOCED = empty,
NOT_AUTHED = empty,
NO_AP_FOUND = empty,
PAIRWISE_CIPHER_INVALID = empty,
UNSPECIFIED = empty,
UNSUPP_RSN_IE_VERSION = empty
}
}
}
},
monitor = {
fields = {
channel = empty,
start = empty,
stop = empty
}
}
}
},
wps = {
fields = {
FAILED = empty,
SCAN_ERR = empty,
SUCCESS = empty,
TIMEOUT = empty,
WEP = empty,
disable = empty,
enable = empty,
start = empty
}
},
ws2801 = {
fields = {
init = empty,
write = empty
}
},
ws2812 = {
fields = {
FADE_IN = empty,
FADE_OUT = empty,
MODE_DUAL = empty,
MODE_SINGLE = empty,
SHIFT_CIRCULAR = empty,
SHIFT_LOGICAL = empty,
init = empty,
newBuffer = empty,
write = empty
}
},
ws2812_effects = {
fields = {
get_delay = empty,
get_speed = empty,
init = empty,
set_brightness = empty,
set_color = empty,
set_delay = empty,
set_mode = empty,
set_speed = empty,
start = empty,
stop = empty
}
},
xpt2046 = {
fields = {
getPosition = empty,
getPositionAvg = empty,
getRaw = empty,
init = empty,
isTouched = empty,
setCalibration = empty
}
},
pack = empty,
unpack = empty,
size = empty
}
}
std = "lua51+nodemcu_libs"
\ No newline at end of file
#!/usr/bin/lua
---
-- Script to extract names and the functions themselves from NodeMCU modules and
-- to help creating luacheck configuration.
-- Usage: <in modules catalog> ../../tools/luacheck_config_helper.lua *.c (or filename for single module)
local M = {}
-- Recursive object dumper, for debugging.
-- (c) 2010 David Manura, MIT License.
-- From: https://github.com/davidm/lua-inspect/blob/master/lib/luainspect/dump.lua
local ignore_keys_ = {lineinfo = true}
local norecurse_keys_ = {parent = true, ast = true}
local function dumpstring_key_(k, isseen, newindent)
local ks = type(k) == 'string' and k:match'^[%a_][%w_]*$' and k or
'[' .. M.dumpstring(k, isseen, newindent) .. ']'
return ks
end
local function sort_keys_(a, b)
if type(a) == 'number' and type(b) == 'number' then
return a < b
elseif type(a) == 'number' then
return false
elseif type(b) == 'number' then
return true
elseif type(a) == 'string' and type(b) == 'string' then
return a < b
else
return tostring(a) < tostring(b) -- arbitrary
end
end
function M.dumpstring(o, isseen, indent, key)
isseen = isseen or {}
indent = indent or ''
if type(o) == 'table' then
if isseen[o] or norecurse_keys_[key] then
return (type(o.tag) == 'string' and '`' .. o.tag .. ':' or '') .. tostring(o)
else isseen[o] = true end -- avoid recursion
local used = {}
local tag = o.tag
local s = '{'
if type(o.tag) == 'string' then
s = '`' .. tag .. s; used['tag'] = true
end
local newindent = indent .. ' '
local ks = {}; for k in pairs(o) do ks[#ks+1] = k end
table.sort(ks, sort_keys_)
local forcenummultiline
for k in pairs(o) do
if type(k) == 'number' and type(o[k]) == 'table' then forcenummultiline = true end
end
-- inline elements
for _,k in ipairs(ks) do
if ignore_keys_[k] then used[k] = true
elseif (type(k) ~= 'number' or not forcenummultiline) and
type(k) ~= 'table' and (type(o[k]) ~= 'table' or norecurse_keys_[k])
then
s = s .. dumpstring_key_(k, isseen, newindent) .. ' = ' .. M.dumpstring(o[k], isseen, newindent, k) .. ', '
used[k] = true
end
end
-- elements on separate lines
local done
for _,k in ipairs(ks) do
if not used[k] then
if not done then s = s .. '\n'; done = true end
s = s .. newindent .. dumpstring_key_(k, isseen) .. ' = ' .. M.dumpstring(o[k], isseen, newindent, k) .. ',\n'
end
end
s = s:gsub(',(%s*)$', '%1')
s = s .. (done and indent or '') .. '}'
return s
elseif type(o) == 'string' then
return string.format('%q', o)
else
return tostring(o)
end
end
-- End of dump.lua code
local function printTables(fileName)
local findBegin, field
if type(fileName) ~= "string" then error("Wrong argument") end
local file = io.open(fileName, "r")
if not file then error("Can't open file") end
local result = {}
result.fields = {}
for line in file:lines() do
findBegin, _, field = string.find(line, "LROT_BEGIN%((%g+)%)")
if findBegin then
io.write(field.." = ")
end
findBegin, _, field = string.find(line, "LROT_PUBLIC_BEGIN%((%g+)%)")
if findBegin then
print(field.." = ")
end
findBegin, _, field = string.find(line, "LROT_FUNCENTRY%(%s?(%g+),")
if not findBegin then
findBegin, _, field = string.find(line, "LROT_NUMENTRY%(%s?(%g+),")
end
if not findBegin then
findBegin, _, field = string.find(line, "LROT_TABENTRY%(%s?(%g+),")
end
if findBegin then
if not string.find(field, "__") then
result.fields[field] = {}
end
end
findBegin = string.find(line, "LROT_END")
if findBegin then
print(string.gsub(M.dumpstring(result), "{}", "empty")..',')
result = {}
result.fields = {}
end
end
end
local function main()
for i = 1, #arg do
printTables(arg[i])
end
end
main()
\ No newline at end of file
#!/usr/bin/env python
#
# ESP8266 LFS Loader Utility
#
# Copyright (C) 2019 Terry Ellison, NodeMCU Firmware Community Project. drawing
# heavily from and including content from esptool.py with full acknowledgement
# under GPL 2.0, with said content: Copyright (C) 2014-2016 Fredrik Ahlberg, Angus
# Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted.
# https:# github.com/espressif/esptool
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
import os
import sys
print os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/toolchains/')
import esptool
import io
import tempfile
import shutil
from pprint import pprint
import argparse
import gzip
import copy
import inspect
import struct
import string
import math
__version__ = '1.0'
__program__ = 'nodemcu-partition.py'
ROM0_Seg = 0x010000
FLASH_PAGESIZE = 0x001000
FLASH_BASE_ADDR = 0x40200000
PARTITION_TYPE = {
4: 'RF_CAL',
5: 'PHY_DATA',
6: 'SYSTEM_PARAMETER',
101: 'EAGLEROM',
102: 'IROM0TEXT',
103: 'LFS0',
104: 'LFS1',
105: 'TLSCERT',
106: 'SPIFFS0',
107: 'SPIFFS1'}
IROM0TEXT = 102
LFS = 103
SPIFFS = 106
MAX_PT_SIZE = 20*3
FLASH_SIG = 0xfafaa150
FLASH_SIG_MASK = 0xfffffff0
FLASH_SIG_ABSOLUTE = 0x00000001
WORDSIZE = 4
WORDBITS = 32
DEFAULT_FLASH_SIZE = 4*1024*1024
PLATFORM_RCR_DELETED = 0x0
PLATFORM_RCR_PT = 0x1
PLATFORM_RCR_FREE = 0xFF
SPIFFS_USE_ALL = 0xFFFFFFFF
PACK_INT = struct.Struct("<I")
class FatalError(RuntimeError):
def __init__(self, message):
RuntimeError.__init__(self, message)
def WithResult(message, result):
message += " (result was %s)" % hexify(result)
return FatalError(message)
def alignPT(n):
return 2*FLASH_PAGESIZE*int(math.ceil(n/2/FLASH_PAGESIZE))
def unpack_RCR(data):
RCRword,recs, i = [PACK_INT.unpack_from(data,i)[0] \
for i in range(0, FLASH_PAGESIZE, WORDSIZE)], \
[],0
while RCRword[i] % 256 != PLATFORM_RCR_FREE:
Rlen, Rtype = RCRword[i] % 256, (RCRword[i]/256) % 256
if Rtype != PLATFORM_RCR_DELETED:
rec = [Rtype,[RCRword[j] for j in range(i+1,i+1+Rlen)]]
if Rtype == PLATFORM_RCR_PT:
PTrec = rec[1]
else:
recs.append(rec)
i = i + Rlen + 1
if PTrec is not None:
return PTrec,recs
FatalError("No partition table found")
def repack_RCR(recs):
data = []
for r in recs:
Rtype, Rdata = r
data.append(256*Rtype + len(Rdata))
data.extend(Rdata)
return ''.join([PACK_INT.pack(i) for i in data])
def load_PT(data, args):
"""
Load the Flash copy of the Partition Table from the first segment of the IROM0
segment, that is at 0x10000. If nececessary the LFS partition is then correctly
positioned and adjusted according to the optional start and len arguments.
The (possibly) updated PT is then returned with the LFS sizing.
"""
PTrec,recs = unpack_RCR(data)
flash_size = args.fs if args.fs is not None else DEFAULT_FLASH_SIZE
# The partition table format is a set of 3*uint32 fields (type, addr, size),
# with the optional last slot being an end marker (0,size,0) where size is
# of the firmware image.
if PTrec[-3] == 0: # Pick out the ROM size and remove the marker
defaultIROM0size = PTrec[-2] - FLASH_BASE_ADDR
del PTrec[-3:]
else:
defaultIROM0size = None
# The SDK objects to zero-length partitions so if the developer sets the
# size of the LFS and/or the SPIFFS partition to 0 then this is removed.
# If it is subsequently set back to non-zero then it needs to be reinserted.
# In reality the sizing algos assume that the LFS follows the IROM0TEXT one
# and SPIFFS is the last partition. We will need to revisit these algos if
# we adopt a more flexible partiton allocation policy. *** BOTCH WARNING ***
for i in range (0, len(PTrec), 3):
if PTrec[i] == IROM0TEXT and args.ls is not None and \
(len(PTrec) == i+3 or PTrec[i+3] != LFS):
PTrec[i+3:i+3] = [LFS, 0, 0]
break
if PTrec[-3] != SPIFFS:
PTrec.extend([SPIFFS, 0, 0])
lastEnd, newPT, map = 0,[], dict()
print " Partition Start Size \n ------------------ ------ ------"
for i in range (0, len(PTrec), 3):
Ptype, Paddr, Psize = PTrec[i:i+3]
if Ptype == IROM0TEXT:
# If the IROM0 partition size is 0 then compute from the IROM0_SIZE.
# Note that this script uses the size in the end-marker as a default
if Psize == 0:
if defaultIROM0size is None:
raise FatalError("Cannot set the IROM0 partition size")
Psize = alignPT(defaultIROM0size)
elif Ptype == LFS:
# Properly align the LFS partition size and make it consecutive to
# the previous partition.
if args.la is not None:
Paddr = args.la
if args.ls is not None:
Psize = args.ls
Psize = alignPT(Psize)
if Paddr == 0:
Paddr = lastEnd
if Psize > 0:
map['LFS'] = {"addr" : Paddr, "size" : Psize}
elif Ptype == SPIFFS:
# The logic here is convolved. Explicit start and length can be
# set, but the SPIFFS region is aslo contrained by the end of the
# previos partition and the end of Flash. The size = -1 value
# means use up remaining flash and the SPIFFS will be moved to the
# 1Mb boundary if the address is default and the specified size
# allows this.
if args.sa is not None:
Paddr = args.sa
if args.ss is not None:
Psize = args.ss if args.ss >= 0 else SPIFFS_USE_ALL
if Psize == SPIFFS_USE_ALL:
# This allocate all the remaining flash to SPIFFS
if Paddr < lastEnd:
Paddr = lastEnd
Psize = flash_size - Paddr
else:
if Paddr == 0:
# if the is addr not specified then start SPIFFS at 1Mb
# boundary if the size will fit otherwise make it consecutive
# to the previous partition.
Paddr = 0x100000 if Psize <= flash_size - 0x100000 else lastEnd
elif Paddr < lastEnd:
Paddr = lastEnd
if Psize > flash_size - Paddr:
Psize = flash_size - Paddr
if Psize > 0:
map['SPIFFS'] = {"addr" : Paddr, "size" : Psize}
if Psize > 0:
Pname = PARTITION_TYPE[Ptype] if Ptype in PARTITION_TYPE \
else ("Type %d" % Ptype)
print(" %-18s %06x %06x"% (Pname, Paddr, Psize))
# Do consistency tests on the partition
if (Paddr & (FLASH_PAGESIZE - 1)) > 0 or \
(Psize & (FLASH_PAGESIZE - 1)) > 0 or \
Paddr < lastEnd or \
Paddr + Psize > flash_size:
print (lastEnd, flash_size)
raise FatalError("Partition %u invalid alignment\n" % (i/3))
newPT.extend([Ptype, Paddr, Psize])
lastEnd = Paddr + Psize
recs.append([PLATFORM_RCR_PT,newPT])
return recs, map
def relocate_lfs(data, addr, size):
"""
The unpacked LFS image comprises the relocatable image itself, followed by a bit
map (one bit per word) flagging if the corresponding word of the image needs
relocating. The image and bitmap are enumerated with any addresses being
relocated by the LFS base address. (Note that the PIC format of addresses is word
aligned and so first needs scaling by the wordsize.)
"""
addr += FLASH_BASE_ADDR
w = [PACK_INT.unpack_from(data,i)[0] for i in range(0, len(data),WORDSIZE)]
flash_sig, flash_size = w[0], w[1]
assert ((flash_sig & FLASH_SIG_MASK) == FLASH_SIG and
(flash_sig & FLASH_SIG_ABSOLUTE) == 0 and
flash_size % WORDSIZE == 0)
flash_size //= WORDSIZE
flags_size = (flash_size + WORDBITS - 1) // WORDBITS
print WORDSIZE*flash_size, size, len(data), WORDSIZE*(flash_size + flags_size)
assert (WORDSIZE*flash_size <= size and
len(data) == WORDSIZE*(flash_size + flags_size))
image,flags,j = w[0:flash_size], w[flash_size:], 0
for i in range(0,len(image)):
if i % WORDBITS == 0:
flag_word = flags[j]
j += 1
if (flag_word & 1) == 1:
o = image[i]
image[i] = WORDSIZE*image[i] + addr
flag_word >>= 1
return ''.join([PACK_INT.pack(i) for i in image])
def main():
def arg_auto_int(x):
ux = x.upper()
if "M" in ux:
return int(ux[:ux.index("M")]) * 1024 * 1024
elif "K" in ux:
return int(ux[:ux.index("K")]) * 1024
else:
return int(ux, 0)
print('%s V%s' %(__program__, __version__))
# ---------- process the arguments ---------- #
a = argparse.ArgumentParser(
description='%s V%s - ESP8266 NodeMCU Loader Utility' %
(__program__, __version__),
prog=__program__)
a.add_argument('--port', '-p', help='Serial port device')
a.add_argument('--baud', '-b', type=arg_auto_int,
help='Serial port baud rate used when flashing/reading')
a.add_argument('--flash_size', '-fs', dest="fs", type=arg_auto_int,
help='Flash size used in SPIFFS allocation (Default 4MB)')
a.add_argument('--lfs_addr', '-la', dest="la", type=arg_auto_int,
help='(Overwrite) start address of LFS partition')
a.add_argument('--lfs_size', '-ls', dest="ls", type=arg_auto_int,
help='(Overwrite) length of LFS partition')
a.add_argument('--lfs_file', '-lf', dest="lf", help='LFS image file')
a.add_argument('--spiffs_addr', '-sa', dest="sa", type=arg_auto_int,
help='(Overwrite) start address of SPIFFS partition')
a.add_argument('--spiffs_size', '-ss', dest="ss", type=arg_auto_int,
help='(Overwrite) length of SPIFFS partition')
a.add_argument('--spiffs_file', '-sf', dest="sf", help='SPIFFS image file')
arg = a.parse_args()
if arg.lf is not None:
if not os.path.exists(arg.lf):
raise FatalError("LFS image %s does not exist" % arg.lf)
if arg.sf is not None:
if not os.path.exists(arg.sf):
raise FatalError("SPIFFS image %s does not exist" % arg.sf)
base = [] if arg.port is None else ['--port',arg.port]
if arg.baud is not None: base.extend(['--baud',arg.baud])
# ---------- Use esptool to read the PT ---------- #
tmpdir = tempfile.mkdtemp()
pt_file = tmpdir + '/pt.dmp'
espargs = base+['--after', 'no_reset', 'read_flash', '--no-progress',
str(ROM0_Seg), str(FLASH_PAGESIZE), pt_file]
esptool.main(espargs)
with open(pt_file,"rb") as f:
data = f.read()
# ---------- Update the PT if necessary ---------- #
recs, pt_map = load_PT(data, arg)
odata = repack_RCR(recs)
odata = odata + "\xFF" * (FLASH_PAGESIZE - len(odata))
# ---------- If the PT has changed then use esptool to rewrite it ---------- #
if odata != data:
print("PT updated")
pt_file = tmpdir + '/opt.dmp'
with open(pt_file,"wb") as f:
f.write(odata)
espargs = base+['--after', 'no_reset', 'write_flash', '--no-progress',
str(ROM0_Seg), pt_file]
esptool.main(espargs)
if arg.lf is not None:
if 'LFS' not in pt_map:
raise FatalError("No LFS partition; cannot write LFS image")
la,ls = pt_map['LFS']['addr'], pt_map['LFS']['size']
# ---------- Read and relocate the LFS image ---------- #
with gzip.open(arg.lf) as f:
lfs = f.read()
if len(lfs) > ls:
raise FatalError("LFS partition to small for LFS image")
lfs = relocate_lfs(lfs, la, ls)
# ---------- Write to a temp file and use esptool to write it to flash ---------- #
img_file = tmpdir + '/lfs.img'
espargs = base + ['write_flash', str(la), img_file]
with open(img_file,"wb") as f:
f.write(lfs)
esptool.main(espargs)
if arg.sf is not None:
if 'SPIFFS' not in pt_map:
raise FatalError("No SPIFSS partition; cannot write SPIFFS image")
sa,ss = pt_map['SPIFFS']['addr'], pt_map['SPIFFS']['size']
# ---------- Write to a temp file and use esptool to write it to flash ---------- #
spiffs_file = arg.sf
espargs = base + ['write_flash', str(sa), spiffs_file]
esptool.main(espargs)
# ---------- Clean up temp directory ---------- #
# espargs = base + ['--after', 'hard_reset', 'flash_id']
# esptool.main(espargs)
shutil.rmtree(tmpdir)
def _main():
main()
if __name__ == '__main__':
_main()
APP_DIR = ../../app
summary ?= @true
CC =gcc
SRCS=\
main.c \
../../app/spiffs/spiffs_cache.c ../../app/spiffs/spiffs_check.c ../../app/spiffs/spiffs_gc.c ../../app/spiffs/spiffs_hydrogen.c ../../app/spiffs/spiffs_nucleus.c
$(APP_DIR)/spiffs/spiffs_cache.c $(APP_DIR)/spiffs/spiffs_check.c $(APP_DIR)/spiffs/spiffs_gc.c $(APP_DIR)/spiffs/spiffs_hydrogen.c $(APP_DIR)/spiffs/spiffs_nucleus.c
CFLAGS=-g -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -I. -I../../app/spiffs -I../../app/include -DNODEMCU_SPIFFS_NO_INCLUDE --include spiffs_typedefs.h -Ddbg_printf=printf
CFLAGS=-g -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -I. -I$(APP_DIR)/spiffs -I$(APP_DIR)/include -DNODEMCU_SPIFFS_NO_INCLUDE --include spiffs_typedefs.h -Ddbg_printf=printf
spiffsimg: $(SRCS)
$(summary) HOSTCC $(CURDIR)/$<
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment