Initial commit with supported platforms: Atmel AVR, TI MSP430 and TI C Series MCU

This commit is contained in:
Ivan Kravets
2014-05-18 23:38:59 +03:00
parent 6e2cf47303
commit 5bee43540c
16 changed files with 877 additions and 1 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.egg-info
*.pyc
.pioenvs
.tox
.sconsign.dblite

3
.isort.cfg Normal file
View File

@ -0,0 +1,3 @@
[settings]
line_length=79
known_third_party=click,clint,serial,SCons

View File

@ -1,4 +1,4 @@
platformio
PlatformIO
==========
An easy way to build code with different development platforms

16
platformio/__init__.py Normal file
View File

@ -0,0 +1,16 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
VERSION = (0, 0, 0)
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"
__description__ = ("An easy way to build code with different development"
"platforms")
__url__ = "https://github.com/ivankravets/platformio"
__author__ = "Ivan Kravets"
__email__ = "me@ikravets.com"
__license__ = "MIT Licence"
__copyright__ = "Copyright (C) 2014 Ivan Kravets"

84
platformio/__main__.py Normal file
View File

@ -0,0 +1,84 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
import click
from sys import exit
from clint.textui import colored, indent, puts
from platformio.util import get_project_config, run_builder
@click.group()
def main():
pass
@main.group()
def init():
""" Initialize new platformio based project """
pass
@main.group()
def install():
""" Install new platforms """
pass
@main.group()
def list():
""" List installed platforms """
pass
@main.command()
@click.option("--environment", "-e", multiple=True)
@click.option("--target", "-t", multiple=True)
def run(environment, target):
"""Process project environments """
config = get_project_config()
for section in config.sections():
if section[:4] != "env:":
continue
envname = section[4:]
if environment and envname not in environment:
puts("Skipped %s environment" % colored.yellow(envname))
continue
puts("Processing %s environment:" % colored.cyan(envname))
variables = ["%s=%s" % (o.upper(), v) for o, v in config.items(section)
if o != "targets"]
variables.append("PIOENV=" + envname)
envtargets = []
if target:
envtargets = [t for t in target]
elif config.has_option(section, "targets"):
envtargets = config.get(section, "targets").split()
result = run_builder(variables, envtargets)
# print result
with indent(4, quote=colored.white(".")):
puts(colored.green(result['out']))
puts(colored.red(result['err']))
@main.group()
def search():
""" Search for new platforms """
pass
@main.group()
def show():
""" Show information about installed platforms """
pass
if __name__ == "__main__":
exit(main())

View File

@ -0,0 +1,2 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.

View File

@ -0,0 +1,54 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
from os.path import isdir, join
from SCons.Script import (DefaultEnvironment, Exit, SConscript,
SConscriptChdir, Variables)
from platformio.util import get_home_dir, get_project_dir, get_source_dir
PIOBUILDER_DIR = join(get_source_dir(), "builder")
# AllowSubstExceptions()
# define user's variables
clivars = Variables(None)
clivars.AddVariables(
("PIOENV",),
("PLATFORM",),
("BOARD",),
("UPLOAD_PORT",)
)
# print sdf
DefaultEnvironment(
tools=["default", "platformio"],
toolpath=[join(PIOBUILDER_DIR, "tools")],
variables=clivars,
PROJECT_DIR=get_project_dir(),
PLATFORMIOHOME_DIR=get_home_dir(),
PLATFORM_DIR=join("$PLATFORMIOHOME_DIR", "${PLATFORM}"),
PLATFORMCORE_DIR=join("$PLATFORM_DIR", "core"),
PLATFORMTOOLS_DIR=join("$PLATFORM_DIR", "tools"),
BUILD_DIR=join("$PROJECT_DIR", ".pioenvs", "${PIOENV}"),
BUILDCORE_DIR=join("$BUILD_DIR", "core"),
BUILDSRC_DIR=join("$BUILD_DIR", "src")
)
PLATFORM = DefaultEnvironment().subst("${PLATFORM}")
if not isdir(DefaultEnvironment().subst("$PLATFORMIOHOME_DIR")):
Exit("You haven't installed any platforms yet. Please use"
"`platformio install` command")
elif not isdir(DefaultEnvironment().subst("$PLATFORM_DIR")):
Exit("An '%s' platform hasn't been installed yet. Please use "
"`platformio install %s` command" % (PLATFORM.upper(),
PLATFORM))
SConscriptChdir(0)
SConscript(join(PIOBUILDER_DIR, "scripts", PLATFORM + ".py"))

View File

@ -0,0 +1,2 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.

View File

@ -0,0 +1,190 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
"""
Builder for Atmel AVR series of microcontrollers
Fully compatible with Arduino programming language (based on Wiring)
"""
from os.path import join
from SCons.Script import (AlwaysBuild, Builder, COMMAND_LINE_TARGETS, Default,
DefaultEnvironment, Exit)
#
# SETUP ENVIRONMENT
#
env = DefaultEnvironment()
BOARD_OPTIONS = env.ParseBoardOptions(join("$PLATFORM_DIR", "boards.txt"),
"${BOARD}")
env.Replace(
ARDUINO_VERSION=open(join(env.subst("$PLATFORM_DIR"),
"version.txt")).read().replace(".", "").strip(),
BOARD_MCU=BOARD_OPTIONS['build.mcu'],
BOARD_F_CPU=BOARD_OPTIONS['build.f_cpu'],
BOARD_VID=BOARD_OPTIONS.get("build.vid", "0"),
BOARD_PID=BOARD_OPTIONS.get("build.pid", "0"),
AR="avr-ar",
AS="avr-as",
CC="avr-gcc",
CXX="avr-g++",
OBJCOPY="avr-objcopy",
RANLIB="avr-ranlib",
ARFLAGS=["rcs"],
ASFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-x", "assembler-with-cpp",
"-mmcu=$BOARD_MCU",
"-DF_CPU=$BOARD_F_CPU",
"-DUSB_VID=$BOARD_VID",
"-DUSB_PID=$BOARD_PID",
"-DARDUINO=$ARDUINO_VERSION"
],
CCFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-Os", # optimize for size
"-Wall", # show warnings
"-fno-exceptions",
"-ffunction-sections", # place each function in its own section
"-fdata-sections",
"-mmcu=$BOARD_MCU",
"-DF_CPU=$BOARD_F_CPU",
"-MMD", # output dependancy info
"-DUSB_VID=$BOARD_VID",
"-DUSB_PID=$BOARD_PID",
"-DARDUINO=$ARDUINO_VERSION"
],
CFLAGS=["-std=gnu99"],
LINKFLAGS=[
"-Os",
"-Wl,--gc-sections" + (",--relax" if BOARD_OPTIONS['build.mcu'] ==
"atmega2560" else ""),
"-mmcu=$BOARD_MCU",
"-lm"
],
CPPPATH=[
"$PLATFORMCORE_DIR",
join("$PLATFORM_DIR", "variants", BOARD_OPTIONS['build.variant'])
],
UPLOADER="avrdude",
UPLOADERFLAGS=[
"-V", # do not verify
"-q", # suppress progress output
"-D", # disable auto erase for flash memory
"-p", "$BOARD_MCU",
"-C", join("$PLATFORMTOOLS_DIR", "avr", "etc", "avrdude.conf"),
"-c", ("stk500v1" if BOARD_OPTIONS['upload.protocol'] == "stk500" else
BOARD_OPTIONS['upload.protocol']),
"-b", BOARD_OPTIONS['upload.speed'],
"-P", "${UPLOAD_PORT}"
],
UPLOADHEXCMD="$UPLOADER $UPLOADERFLAGS -U flash:w:$SOURCES:i",
UPLOADEEPCMD="$UPLOADER $UPLOADERFLAGS -U eeprom:w:$SOURCES:i"
)
env.Append(
BUILDERS=dict(
ElfToEep=Builder(
action=" ".join([
"$OBJCOPY",
"-O",
"ihex",
"-j",
".eeprom",
'--set-section-flags=.eeprom="alloc,load"',
"--no-change-warnings",
"--change-section-lma",
".eeprom=0",
"$SOURCES",
"$TARGET"]),
suffix=".eep"
),
ElfToHex=Builder(
action=" ".join([
"$OBJCOPY",
"-O",
"ihex",
"-R",
".eeprom",
"$SOURCES",
"$TARGET"]),
suffix=".hex"
)
)
)
env.PrependENVPath(
"PATH",
join(env.subst("$PLATFORMTOOLS_DIR"), "avr", "bin")
)
#
# Target: Build Core Library
#
target_corelib = env.BuildCoreLibrary()
#
# Target: Build executable and linkable firmware
#
target_elf = env.BuildFirmware([target_corelib])
#
# Target: Extract EEPROM data (from EEMEM directive) to .eep file
#
target_eep = env.ElfToEep(join("$BUILD_DIR", "firmware"), target_elf)
#
# Target: Build the .hex file
#
target_hex = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf)
#
# Target: Upload .eep file
#
eep = env.Alias("eep", target_eep, [
lambda target, source, env: env.ResetDevice(), "$UPLOADEEPCMD"])
AlwaysBuild(eep)
#
# Target: Upload .hex file
#
upload = env.Alias("upload", target_hex, [
lambda target, source, env: env.ResetDevice(), "$UPLOADHEXCMD"])
AlwaysBuild(upload)
#
# Target: Define targets
#
env.Alias("build-eep", [target_eep])
Default([target_corelib, target_elf, target_hex])
# check for $UPLOAD_PORT variable
is_uptarget = ("eep" in COMMAND_LINE_TARGETS or "upload" in
COMMAND_LINE_TARGETS)
if is_uptarget and not env.subst("$UPLOAD_PORT"):
Exit("Please specify 'upload_port'")

View File

@ -0,0 +1,137 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
"""
Builder for Texas Instruments
MSP430 Ultra-Low Power 16-bit microcontrollers
Fully compatible with Energia programming language (based on Wiring).
"""
from os.path import join
from SCons.Script import AlwaysBuild, Builder, Default, DefaultEnvironment
#
# SETUP ENVIRONMENT
#
env = DefaultEnvironment()
BOARD_OPTIONS = env.ParseBoardOptions(join("$PLATFORM_DIR", "boards.txt"),
"${BOARD}")
env.Replace(
# See https://github.com/energia/Energia/blob/master/app/src/
# processing/app/Base.java#L45
ARDUINO_VERSION="101",
ENERGIA_VERSION="12",
BOARD_MCU=BOARD_OPTIONS['build.mcu'],
BOARD_F_CPU=BOARD_OPTIONS['build.f_cpu'],
AR="msp430-ar",
AS="msp430-as",
CC="msp430-gcc",
CXX="msp430-g++",
OBJCOPY="msp430-objcopy",
RANLIB="msp430-ranlib",
ARFLAGS=["rcs"],
ASFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-assembler-with-cpp",
"-mmcu=$BOARD_MCU",
"-DF_CPU=$BOARD_F_CPU",
"-DARDUINO=$ARDUINO_VERSION",
"-DENERGIA=$ENERGIA_VERSION"
],
CCFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-Os", # optimize for size
"-Wall", # show warnings
"-ffunction-sections", # place each function in its own section
"-fdata-sections",
"-mmcu=$BOARD_MCU",
"-DF_CPU=$BOARD_F_CPU",
"-MMD", # output dependancy info
"-DARDUINO=$ARDUINO_VERSION",
"-DENERGIA=$ENERGIA_VERSION"
],
LINK="$CC",
LINKFLAGS=[
"-Os",
"-mmcu=$BOARD_MCU",
"-Wl,-gc-sections,-u,main"
],
CPPPATH=[
"$PLATFORMCORE_DIR",
join("$PLATFORM_DIR", "variants", BOARD_OPTIONS['build.variant'])
],
UPLOADER=(join("$PLATFORMTOOLS_DIR", "msp430", "mspdebug", "mspdebug")),
UPLOADERFLAGS=[
BOARD_OPTIONS['upload.protocol'],
"--force-reset"
],
UPLOADCMD='$UPLOADER $UPLOADERFLAGS "prog $SOURCES"'
)
env.Append(
BUILDERS=dict(
ElfToHex=Builder(
action=" ".join([
"$OBJCOPY",
"-O",
"ihex",
"-R",
".eeprom",
"$SOURCES",
"$TARGET"]),
suffix=".hex"
)
)
)
env.PrependENVPath(
"PATH",
join(env.subst("$PLATFORMTOOLS_DIR"), "msp430", "bin")
)
#
# Target: Build Core Library
#
target_corelib = env.BuildCoreLibrary()
#
# Target: Build executable and linkable firmware
#
target_elf = env.BuildFirmware([target_corelib, "m"])
#
# Target: Build the .hex
#
target_hex = env.ElfToHex(join("$BUILD_DIR", "firmware"), target_elf)
#
# Target: Upload firmware
#
upload = env.Alias("upload", target_hex, ["$UPLOADCMD"])
AlwaysBuild(upload)
#
# Target: Define targets
#
Default([target_corelib, target_elf, target_hex])

View File

@ -0,0 +1,152 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
"""
Builder for Texas Instruments
Tiva C Series ARM Cortex-M4 microcontrollers.
Fully compatible with Energia programming language (based on Wiring).
"""
from os.path import join
from SCons.Script import AlwaysBuild, Builder, Default, DefaultEnvironment
#
# SETUP ENVIRONMENT
#
env = DefaultEnvironment()
BOARD_OPTIONS = env.ParseBoardOptions(join("$PLATFORM_DIR", "boards.txt"),
"${BOARD}")
env.Replace(
ARDUINO_VERSION="101",
ENERGIA_VERSION="12",
BOARD_MCU=BOARD_OPTIONS['build.mcu'],
BOARD_F_CPU=BOARD_OPTIONS['build.f_cpu'],
AR="arm-none-eabi-ar",
AS="arm-none-eabi-as",
CC="arm-none-eabi-gcc",
CXX="arm-none-eabi-g++",
OBJCOPY="arm-none-eabi-objcopy",
RANLIB="arm-none-eabi-ranlib",
ARFLAGS=["rcs"],
ASFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-assembler-with-cpp",
"-Wall",
"-mthumb",
"-mcpu=cortex-m4",
"-mfloat-abi=hard",
"-mfpu=fpv4-sp-d16",
"-fsingle-precision-constant",
"-DF_CPU=$BOARD_F_CPU",
"-DARDUINO=$ARDUINO_VERSION",
"-DENERGIA=$ENERGIA_VERSION"
],
CCFLAGS=[
"-g", # include debugging info (so errors include line numbers)
"-Os", # optimize for size
"-Wall", # show warnings
"-ffunction-sections", # place each function in its own section
"-fdata-sections",
"-Wall",
"-mthumb",
"-mcpu=cortex-m4",
"-mfloat-abi=hard",
"-mfpu=fpv4-sp-d16",
"-fsingle-precision-constant",
"-DF_CPU=$BOARD_F_CPU",
"-MMD", # output dependancy info
"-DARDUINO=$ARDUINO_VERSION",
"-DENERGIA=$ENERGIA_VERSION"
],
CXXFLAGS=[
"-fno-rtti",
"-fno-exceptions"
],
LINKFLAGS=[
"-Os",
"-nostartfiles",
"-nostdlib",
"-Wl,--gc-sections",
"-T", join("$PLATFORMCORE_DIR", BOARD_OPTIONS['ldscript']),
"-Wl,--entry=ResetISR",
"-mthumb",
"-mcpu=cortex-m4",
"-mfloat-abi=hard",
"-mfpu=fpv4-sp-d16",
"-fsingle-precision-constant"
],
CPPPATH=[
"$PLATFORMCORE_DIR",
join("$PLATFORM_DIR", "variants", BOARD_OPTIONS['build.variant'])
],
UPLOADER="lm4flash",
UPLOADCMD="$UPLOADER $SOURCES"
)
env.Append(
BUILDERS=dict(
ElfToBin=Builder(
action=" ".join([
"$OBJCOPY",
"-O",
"binary",
"$SOURCES",
"$TARGET"]),
suffix=".hex"
)
)
)
env.PrependENVPath(
"PATH",
join(env.subst("$PLATFORMTOOLS_DIR"), "lm4f", "bin")
)
#
# Target: Build Core Library
#
target_corelib = env.BuildCoreLibrary()
#
# Target: Build executable and linkable firmware
#
target_elf = env.BuildFirmware([target_corelib, "c", "gcc", "m"])
#
# Target: Build the .bin file
#
target_bin = env.ElfToBin(join("$BUILD_DIR", "firmware"), target_elf)
#
# Target: Upload firmware
#
upload = env.Alias("upload", target_bin, ["$UPLOADCMD"])
AlwaysBuild(upload)
#
# Target: Define targets
#
Default([target_corelib, target_elf, target_bin])

View File

@ -0,0 +1,2 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.

View File

@ -0,0 +1,98 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
from os import walk
from os.path import isfile, join
from time import sleep
from serial import Serial
def BuildCoreLibrary(env):
corelib = env.Clone()
vdirs = corelib.VariantDirRecursive("$BUILDCORE_DIR", "$PLATFORMCORE_DIR")
return corelib.Library(
corelib.subst("$BUILDCORE_DIR"),
[corelib.GlobCXXFiles(vdir) for vdir in vdirs]
)
def BuildFirmware(env, liblist):
src = env.Clone()
vdirs = src.VariantDirRecursive("$BUILDSRC_DIR",
join("$PROJECT_DIR", "src"))
return src.Program(
join("$BUILD_DIR", "firmware"),
[src.GlobCXXFiles(vdir) for vdir in vdirs],
LIBS=liblist,
LIBPATH="$BUILD_DIR",
PROGSUFFIX=".elf")
def GlobCXXFiles(env, path):
files = []
for suff in ["*.c", "*.cpp", "*.S"]:
_list = env.Glob(join(path, suff))
if _list:
files += _list
return files
def VariantDirRecursive(env, variant_dir, src_dir, duplicate=True):
# add root dir by default
variants = [variant_dir]
env.VariantDir(variant_dir, src_dir, duplicate)
for root, dirnames, filenames in walk(env.subst(src_dir)):
if not dirnames:
continue
for dn in dirnames:
env.VariantDir(join(variant_dir, dn), join(root, dn), duplicate)
variants.append(join(variant_dir, dn))
return variants
def ParseBoardOptions(env, path, name):
path = env.subst(path)
name = env.subst(name)
if not isfile(path):
env.Exit("Invalid path to boards.txt -> %s" % path)
data = {}
_namelen = len(name) + 1
with open(path) as f:
for line in f:
if line[0:_namelen] != name + ".":
continue
line = line[_namelen:].strip()
opt, value = line.split("=", 1)
data[opt] = value
if not data:
env.Exit("Unknown Board '%s'" % name)
else:
return data
def ResetDevice(env):
""" Pulse the DTR line and flush serial buffer """
s = Serial(env.subst("$UPLOAD_PORT"))
s.flushInput()
s.setDTR(False)
s.setRTS(False)
sleep(0.1)
s.setDTR(True)
s.setRTS(True)
s.close()
def exists(env):
return True
def generate(env):
env.AddMethod(BuildCoreLibrary)
env.AddMethod(BuildFirmware)
env.AddMethod(GlobCXXFiles)
env.AddMethod(VariantDirRecursive)
env.AddMethod(ParseBoardOptions)
env.AddMethod(ResetDevice)
return env

67
platformio/util.py Normal file
View File

@ -0,0 +1,67 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
from sys import exit
from os import getcwd
from os.path import dirname, expanduser, join, realpath, isfile
from subprocess import Popen, PIPE
try:
from configparser import ConfigParser
except ImportError:
from ConfigParser import ConfigParser
def get_home_dir():
return expanduser("~/.platformio")
def get_source_dir():
return dirname(realpath(__file__))
def get_project_dir():
return getcwd()
def get_project_config():
try:
return getattr(get_project_config, "_cache")
except AttributeError:
pass
path = join(get_project_dir(), "platformio.ini")
if not isfile(path):
exit("Not a platformio project. Use `platformio init` command")
get_project_config._cache = ConfigParser()
get_project_config._cache.read(path)
return get_project_config._cache
def exec_command(args):
p = Popen(args, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
result = dict(out=out.strip(), err=err.strip())
# fix STDERR "flash written"
if "flash written" in result['err']:
result['out'] += "\n" + result['err']
result['err'] = ""
return result
def run_builder(variables, targets):
assert isinstance(variables, list)
assert isinstance(targets, list)
if "clean" in targets:
targets.remove("clean")
targets.append("-c")
return exec_command([
"scons",
"-Q",
"-f", join(get_source_dir(), "builder", "main.py")
] + variables + targets)

42
setup.py Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
from setuptools import find_packages, setup
from platformio import (__author__, __description__, __email__, __license__,
__title__, __url__, __version__)
setup(
name=__title__,
version=__version__,
description=__description__,
long_description=open("README.rst").read(),
author=__author__,
author_email=__email__,
url=__url__,
license=__license__,
install_requires=[
"click",
"clint",
"pyserial"
"SCons"
],
packages=find_packages(),
entry_points={
"console_scripts": [
"platformio = platformio.__main__:main"
]
},
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: C",
"Programming Language :: Python",
"Topic :: Software Development",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Compilers"
]
)

22
tox.ini Normal file
View File

@ -0,0 +1,22 @@
[tox]
envlist = develop, lint
[testenv]
envlogdir = /tmp/toxlogdir
envtmpdir = /tmp/toxtmpdir
commands =
{envpython} --version
[testenv:develop]
usedevelop = True
deps =
isort
flake8
[testenv:lint]
deps =
flake8
pylint
commands =
flake8 ./platformio
pylint --rcfile=./.pylintrc ./platformio