Implement uploading files to file system SPIFFS for ESP8266 // Issue #382

This commit is contained in:
Ivan Kravets
2015-12-28 01:15:06 +02:00
parent d7673b69e2
commit cae5f1f553
14 changed files with 171 additions and 39 deletions

View File

@ -10,6 +10,8 @@ PlatformIO 2.0
* Moved SCons to PlatformIO packages. PlatformIO does not require SCons to be * Moved SCons to PlatformIO packages. PlatformIO does not require SCons to be
installed in your system. Significantly simplified installation process of installed in your system. Significantly simplified installation process of
PlatformIO. ``pip install platformio`` rocks! PlatformIO. ``pip install platformio`` rocks!
* Implemented uploading files to file system SPIFFS for ESP8266
(`issue #382 <https://github.com/platformio/platformio/issues/382>`_)
* Added support for the new Adafruit boards Bluefruit Micro and Feather * Added support for the new Adafruit boards Bluefruit Micro and Feather
(`issue #403 <https://github.com/platformio/platformio/issues/403>`_) (`issue #403 <https://github.com/platformio/platformio/issues/403>`_)
* Added support for RFDuino * Added support for RFDuino

View File

@ -55,6 +55,10 @@ Allows to override :ref:`projectconf` option :ref:`projectconf_pio_src_dir`.
Allows to override :ref:`projectconf` option :ref:`projectconf_pio_envs_dir`. Allows to override :ref:`projectconf` option :ref:`projectconf_pio_envs_dir`.
.. envvar:: PLATFORMIO_DATA_DIR
Allows to override :ref:`projectconf` option :ref:`projectconf_pio_data_dir`.
Builder Builder
------- -------

View File

@ -113,6 +113,9 @@ Packages
* - ``tool-micronucleus`` * - ``tool-micronucleus``
- `Micronucleus <https://github.com/micronucleus/micronucleus>`_ - `Micronucleus <https://github.com/micronucleus/micronucleus>`_
* - ``tool-mkspiffs``
- `Tool to build and unpack SPIFFS images <https://github.com/igrr/mkspiffs>`_
* - ``tool-mspdebug`` * - ``tool-mspdebug``
- `MSPDebug <http://mspdebug.sourceforge.net/>`_ - `MSPDebug <http://mspdebug.sourceforge.net/>`_

View File

@ -28,21 +28,24 @@ Packages
* - Name * - Name
- Contents - Contents
* - ``toolchain-xtensa``
- `xtensa-gcc <https://github.com/jcmvbkbc/gcc-xtensa>`_, `GDB <http://www.gnu.org/software/gdb/>`_
* - ``tool-esptool``
- `esptool-ck <https://github.com/igrr/esptool-ck>`_
* - ``tool-mkspiffs``
- `Tool to build and unpack SPIFFS images <https://github.com/igrr/mkspiffs>`_
* - ``framework-arduinoespressif``
- `Arduino Wiring-based Framework (ESP8266 Core) <https://github.com/esp8266/Arduino>`_
* - ``ldscripts`` * - ``ldscripts``
- `Linker Scripts <https://sourceware.org/binutils/docs/ld/Scripts.html>`_ - `Linker Scripts <https://sourceware.org/binutils/docs/ld/Scripts.html>`_
* - ``sdk-esp8266`` * - ``sdk-esp8266``
- `ESP8266 SDK <http://bbs.espressif.com>`_ - `ESP8266 SDK <http://bbs.espressif.com>`_
* - ``tool-esptool``
- `esptool-ck <https://github.com/igrr/esptool-ck>`_
* - ``framework-arduinoespressif``
- `Arduino Wiring-based Framework (ESP8266 Core) <https://github.com/esp8266/Arduino>`_
* - ``toolchain-xtensa``
- `xtensa-gcc <https://github.com/jcmvbkbc/gcc-xtensa>`_, `GDB <http://www.gnu.org/software/gdb/>`_
.. warning:: .. warning::
**Linux Users:** Don't forget to install "udev" rules file **Linux Users:** Don't forget to install "udev" rules file
`99-platformio-udev.rules <https://github.com/platformio/platformio/blob/develop/scripts/99-platformio-udev.rules>`_ (an instruction is located in the file). `99-platformio-udev.rules <https://github.com/platformio/platformio/blob/develop/scripts/99-platformio-udev.rules>`_ (an instruction is located in the file).

View File

@ -23,6 +23,7 @@ from :ref:`projectconf`
upload_speed = 9600 upload_speed = 9600
.. _platform_espressif_customflash:
Custom Flash Size Custom Flash Size
----------------- -----------------
@ -39,8 +40,6 @@ The list with preconfigured LD scripts is located in public repository
* ``esp8266.flash.2m.ld`` 2M (1M SPIFFS) * ``esp8266.flash.2m.ld`` 2M (1M SPIFFS)
* ``esp8266.flash.4m1.ld`` 4M (1M SPIFFS) * ``esp8266.flash.4m1.ld`` 4M (1M SPIFFS)
* ``esp8266.flash.4m.ld`` 4M (3M SPIFFS) * ``esp8266.flash.4m.ld`` 4M (3M SPIFFS)
* ``esp8266.flash.8m.ld`` 8M (7M SPIFFS)
* ``esp8266.flash.16m.ld`` 16M (15M SPIFFS)
To override default LD script please use :ref:`projectconf_build_flags` from To override default LD script please use :ref:`projectconf_build_flags` from
:ref:`projectconf`. :ref:`projectconf`.
@ -50,6 +49,18 @@ To override default LD script please use :ref:`projectconf_build_flags` from
[env:myenv] [env:myenv]
build_flags = -Wl,-Tesp8266.flash.4m.ld build_flags = -Wl,-Tesp8266.flash.4m.ld
.. _platform_espressif_uploadfs:
Uploading files to file system SPIFFS
-------------------------------------
1. Put files to :ref:`projectconf_pio_data_dir`
2. Run target ``uploadfs`` via :option:`platformio run --target` command.
By default, will be used default LD Script for the board where is specified
SPIFFS flash data (start, end, page, block). You can override it using
:ref:`platform_espressif_customflash`.
Over-the-Air (OTA) update Over-the-Air (OTA) update
------------------------- -------------------------

View File

@ -115,6 +115,18 @@ This option can be overridden by global environment variable
are defined in :ref:`projectconf`, then **TRY TO DELETE** this folder. In are defined in :ref:`projectconf`, then **TRY TO DELETE** this folder. In
this situation you will remove all cached files without any risk. this situation you will remove all cached files without any risk.
.. _projectconf_pio_data_dir:
``data_dir``
^^^^^^^^^^^^
Data directory to store contents and :ref:`platform_espressif_uploadfs`.
A default value is ``%project_dir%/data``.
This option can be overridden by global environment variable
:envvar:`PLATFORMIO_DATA_DIR`.
[env:NAME] [env:NAME]
---------- ----------
@ -463,8 +475,9 @@ Example, specify own upload command for :ref:`platform_atmelavr`:
^^^^^^^^^^^ ^^^^^^^^^^^
A list with targets which will be processed by :ref:`cmd_run` command by A list with targets which will be processed by :ref:`cmd_run` command by
default. You can enter more than one target separated with "space". Which default. You can enter more than one target separated with "space".
targets are supported is described in :option:`platformio run --target`.
The list with available targets is located in :option:`platformio run --target`.
**Tip!** You can use these targets like an option to **Tip!** You can use these targets like an option to
:option:`platformio run --target` command. For example: :option:`platformio run --target` command. For example:

View File

@ -53,6 +53,7 @@ Pre-built targets:
* ``program`` firmware "auto-uploading" for embedded platforms using external * ``program`` firmware "auto-uploading" for embedded platforms using external
programmer (available only for :ref:`platform_atmelavr`) programmer (available only for :ref:`platform_atmelavr`)
* ``uploadlazy`` upload existing firmware without project rebuilding * ``uploadlazy`` upload existing firmware without project rebuilding
* ``uploadfs`` :ref:`platform_espressif_uploadfs`
* ``envdump`` dump current build environment * ``envdump`` dump current build environment
* ``size`` print the size of the sections in a firmware/program * ``size`` print the size of the sections in a firmware/program

View File

@ -14,7 +14,7 @@
import sys import sys
VERSION = (2, 7, "0.dev1") VERSION = (2, 7, "0.dev2")
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"

View File

@ -76,6 +76,7 @@ DefaultEnvironment(
PROJECT_DIR=util.get_project_dir(), PROJECT_DIR=util.get_project_dir(),
PROJECTLIB_DIR=util.get_projectlib_dir(), PROJECTLIB_DIR=util.get_projectlib_dir(),
PROJECTSRC_DIR=util.get_projectsrc_dir(), PROJECTSRC_DIR=util.get_projectsrc_dir(),
PROJECTDATA_DIR=util.get_projectdata_dir(),
PIOENVS_DIR=util.get_pioenvs_dir(), PIOENVS_DIR=util.get_pioenvs_dir(),
PIOBUILDER_DIR=join(util.get_source_dir(), "builder"), PIOBUILDER_DIR=join(util.get_source_dir(), "builder"),

View File

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# pylint: disable=redefined-outer-name
""" """
Builder for Espressif MCUs Builder for Espressif MCUs
""" """
@ -24,22 +26,14 @@ from SCons.Script import (COMMAND_LINE_TARGETS, AlwaysBuild, Builder, Default,
DefaultEnvironment) DefaultEnvironment)
def BeforeUpload(target, source, env): # pylint: disable=W0613,W0621 def _get_flash_size(env):
env.AutodetectUploadPort()
def _get_flash_size(env): # pylint: disable=redefined-outer-name
# use board's flash size by default # use board's flash size by default
board_max_size = int( board_max_size = int(
env.get("BOARD_OPTIONS", {}).get("upload", {}).get("maximum_size", 0)) env.get("BOARD_OPTIONS", {}).get("upload", {}).get("maximum_size", 0))
# check if user overrides # check if user overrides LD Script
for f in env.get("LINKFLAGS", []): match = re.search(r"\.flash\.(\d+)(m|k).*\.ld", env.GetActualLDScript())
if "-Wl,-T" not in f: if match:
continue
match = re.search(r"-Wl,-T.*\.flash\.(\d+)(m|k).*\.ld", env.subst(f))
if not match:
continue
if match.group(2) == "k": if match.group(2) == "k":
board_max_size = int(match.group(1)) * 1024 board_max_size = int(match.group(1)) * 1024
elif match.group(2) == "m": elif match.group(2) == "m":
@ -106,9 +100,13 @@ env.Replace(
"-Wl,--gc-sections" "-Wl,--gc-sections"
], ],
SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES', #
# Upload
#
UPLOADER=join("$PIOPACKAGES_DIR", "tool-esptool", "esptool"), UPLOADER=join("$PIOPACKAGES_DIR", "tool-esptool", "esptool"),
UPLOADEROTA=join("$PLATFORMFW_DIR", "tools", "espota.py"),
UPLOADERFLAGS=[ UPLOADERFLAGS=[
"-vv", "-vv",
"-cd", "${BOARD_OPTIONS['upload']['resetmethod']}", "-cd", "${BOARD_OPTIONS['upload']['resetmethod']}",
@ -116,7 +114,27 @@ env.Replace(
"-cp", "$UPLOAD_PORT", "-cp", "$UPLOAD_PORT",
"-cf", "$SOURCE" "-cf", "$SOURCE"
], ],
UPLOADERFSFLAGS=[
"$UPLOADERFLAGS",
"-ca", "${int(SPIFFS_START, 16)}"
],
UPLOADEROTAFLAGS=[
"--debug",
"--progress",
"-i", "$UPLOAD_PORT",
"-f", "$SOURCE"
],
UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS', UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS',
UPLOADFSCMD='"$UPLOADER" $UPLOADERFSFLAGS',
UPLOADOTACMD='"$UPLOADEROTA" $UPLOADEROTAFLAGS',
#
# Misc
#
MKSPIFFSTOOL=join("$PIOPACKAGES_DIR", "tool-mkspiffs", "mkspiffs"),
SIZEPRINTCMD='"$SIZETOOL" -B -d $SOURCES',
PROGNAME="firmware", PROGNAME="firmware",
PROGSUFFIX=".elf" PROGSUFFIX=".elf"
@ -149,6 +167,48 @@ env.Append(
) )
) )
#
# SPIFFS
#
def _fetch_spiffs_size(target, source, env):
spiffs_re = re.compile(
r"PROVIDE\s*\(\s*_SPIFFS_(\w+)\s*=\s*(0x[\dA-F]+)\s*\)")
with open(env.GetActualLDScript()) as f:
for line in f.readlines():
match = spiffs_re.search(line)
if not match:
continue
env["SPIFFS_%s" % match.group(1).upper()] = match.group(2)
assert all([k in env for k in ["SPIFFS_START", "SPIFFS_END", "SPIFFS_PAGE",
"SPIFFS_BLOCK"]])
return (target, source)
env.Append(
BUILDERS=dict(
DataToBin=Builder(
action=" ".join([
'"$MKSPIFFSTOOL"',
"-c", "$SOURCES",
"-p", "${int(SPIFFS_PAGE, 16)}",
"-b", "${int(SPIFFS_BLOCK, 16)}",
"-s", "${int(SPIFFS_END, 16) - int(SPIFFS_START, 16)}",
"$TARGET"
]),
emitter=_fetch_spiffs_size,
source_factory=env.Dir,
suffix=".bin"
)
)
)
#
# Framework and SDK specific configuration
#
if "FRAMEWORK" in env: if "FRAMEWORK" in env:
env.Append( env.Append(
LINKFLAGS=[ LINKFLAGS=[
@ -161,14 +221,7 @@ if "FRAMEWORK" in env:
try: try:
if env.get("UPLOAD_PORT") and socket.inet_aton(env.get("UPLOAD_PORT")): if env.get("UPLOAD_PORT") and socket.inet_aton(env.get("UPLOAD_PORT")):
env.Replace( env.Replace(
UPLOADEROTA=join("$PLATFORMFW_DIR", "tools", "espota.py"), UPLOADCMD="$UPLOADOTACMD"
UPLOADERFLAGS=[
"--debug",
"--progress",
"-i", "$UPLOAD_PORT",
"-f", "$SOURCE"
],
UPLOADCMD='"$UPLOADEROTA" $UPLOADERFLAGS'
) )
except socket.error: except socket.error:
pass pass
@ -256,9 +309,21 @@ AlwaysBuild(target_size)
# Target: Upload firmware # Target: Upload firmware
# #
upload = env.Alias(["upload", "uploadlazy"], target_firm, target_upload = env.Alias(
[BeforeUpload, "$UPLOADCMD"]) ["upload", "uploadlazy"], target_firm,
AlwaysBuild(upload) [lambda target, source, env: env.AutodetectUploadPort(), "$UPLOADCMD"])
env.AlwaysBuild(target_upload)
#
# Target: Upload SPIFFS image
#
target_mkspiffs = env.DataToBin(join("$BUILD_DIR", "spiffs_image"),
"$PROJECTDATA_DIR")
target_uploadfs = env.Alias(
"uploadfs", target_mkspiffs,
[lambda target, source, env: env.AutodetectUploadPort(), "$UPLOADFSCMD"])
env.AlwaysBuild(target_mkspiffs, target_uploadfs)
# #
# Target: Define targets # Target: Define targets

View File

@ -18,7 +18,7 @@ import atexit
import re import re
from glob import glob from glob import glob
from os import environ, remove from os import environ, remove
from os.path import basename, join from os.path import basename, isfile, join
from platformio.util import exec_command, where_is_program from platformio.util import exec_command, where_is_program
@ -190,6 +190,19 @@ def GetCompilerType(env):
return None return None
def GetActualLDScript(env):
for f in env.get("LINKFLAGS", []):
if f.startswith("-Wl,-T"):
script = env.subst(f[6:].replace('"', "").strip())
if isfile(script):
return script
for d in env.get("LIBPATH", []):
path = join(env.subst(d), script)
if isfile(path):
return path
return None
def exists(_): def exists(_):
return True return True
@ -198,4 +211,5 @@ def generate(env):
env.AddMethod(ConvertInoToCpp) env.AddMethod(ConvertInoToCpp)
env.AddMethod(DumpIDEData) env.AddMethod(DumpIDEData)
env.AddMethod(GetCompilerType) env.AddMethod(GetCompilerType)
env.AddMethod(GetActualLDScript)
return env return env

View File

@ -146,6 +146,10 @@ PLATFORM_PACKAGES = {
], ],
"tool-rfdloader": [ "tool-rfdloader": [
("rfdloader", "https://github.com/RFduino/RFduino") ("rfdloader", "https://github.com/RFduino/RFduino")
],
"tool-mkspiffs": [
("Tool to build and unpack SPIFFS images",
"https://github.com/igrr/mkspiffs")
] ]
} }

View File

@ -41,6 +41,10 @@ class EspressifPlatform(BasePlatform):
"default": True "default": True
}, },
"tool-mkspiffs": {
"alias": "uploader"
},
"sdk-esp8266": { "sdk-esp8266": {
}, },

View File

@ -200,6 +200,13 @@ def get_pioenvs_dir():
) )
def get_projectdata_dir():
return _get_projconf_option_dir(
"data_dir",
join(get_project_dir(), "data")
)
def get_project_config(): def get_project_config():
path = join(get_project_dir(), "platformio.ini") path = join(get_project_dir(), "platformio.ini")
if not isfile(path): if not isfile(path):