From d3b9322d3bad2e983c500865721516456256cf11 Mon Sep 17 00:00:00 2001 From: Valeriy Koval Date: Mon, 9 Mar 2015 12:27:54 +0200 Subject: [PATCH] Initial support for MBED Framework --- examples/mbed/mbed-blink/README.rst | 21 +++ examples/mbed/mbed-blink/platformio.ini | 43 ++++++ examples/mbed/mbed-blink/src/main.cpp | 12 ++ platformio/builder/scripts/frameworks/mbed.py | 140 ++++++++++++++++++ platformio/builder/tools/pioupload.py | 26 +++- platformio/util.py | 29 +++- scripts/mbed_to_package.py | 64 ++++++++ 7 files changed, 326 insertions(+), 9 deletions(-) create mode 100644 examples/mbed/mbed-blink/README.rst create mode 100644 examples/mbed/mbed-blink/platformio.ini create mode 100644 examples/mbed/mbed-blink/src/main.cpp create mode 100644 platformio/builder/scripts/frameworks/mbed.py create mode 100644 scripts/mbed_to_package.py diff --git a/examples/mbed/mbed-blink/README.rst b/examples/mbed/mbed-blink/README.rst new file mode 100644 index 00000000..b36ea0e3 --- /dev/null +++ b/examples/mbed/mbed-blink/README.rst @@ -0,0 +1,21 @@ +How to buid PlatformIO based project +==================================== + +1. `Install PlatformIO `_ +2. Download `source code with examples `_ +3. Extract ZIP archive +4. Run these commands: + +.. code-block:: bash + + # Change directory to example + > cd platformio-develop/examples/mbed/mbed-blink + + # Process example project + > platformio run + + # Upload firmware + > platformio run --target upload + + # Clean build files + > platformio run --target clean diff --git a/examples/mbed/mbed-blink/platformio.ini b/examples/mbed/mbed-blink/platformio.ini new file mode 100644 index 00000000..bbef0cbe --- /dev/null +++ b/examples/mbed/mbed-blink/platformio.ini @@ -0,0 +1,43 @@ +# +# Project Configuration File +# +# A detailed documentation with the EXAMPLES is located here: +# http://docs.platformio.org/en/latest/projectconf.html +# + +# A sign `#` at the beginning of the line indicates a comment +# Comment lines are ignored. + +# Simple and base environment +# [env:mybaseenv] +# platform = %INSTALLED_PLATFORM_NAME_HERE% +# framework = +# board = +# +# Automatic targets - enable auto-uploading +# targets = upload + + +# NXP LPC Platform +[env:lpc1768] +platform = nxplpc +framework = mbed +board = lpc1768 + +# Nordic nRF51 Platform +[env:nrf51_mkit] +platform = nordicnrf51 +framework = mbed +board = nrf51_mkit + +# Freescale FRDM Platform +[env:frdm_k64f] +platform = freescalekinetis +framework = mbed +board = frdm_k64f + +# ST STM32 Platform +[env:nucleo_f401re] +platform = ststm32 +framework = mbed +board = nucleo_f401re \ No newline at end of file diff --git a/examples/mbed/mbed-blink/src/main.cpp b/examples/mbed/mbed-blink/src/main.cpp new file mode 100644 index 00000000..8247a2e9 --- /dev/null +++ b/examples/mbed/mbed-blink/src/main.cpp @@ -0,0 +1,12 @@ +#include "mbed.h" + +DigitalOut myled(LED1); + +int main() { + while(1) { + myled = 1; + wait(1); + myled = 0; + wait(1); + } +} \ No newline at end of file diff --git a/platformio/builder/scripts/frameworks/mbed.py b/platformio/builder/scripts/frameworks/mbed.py new file mode 100644 index 00000000..03f54616 --- /dev/null +++ b/platformio/builder/scripts/frameworks/mbed.py @@ -0,0 +1,140 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +""" + Build script for Mbed Framework +""" + +import xml.etree.ElementTree as ElementTree +from binascii import crc32 +from os.path import join, normpath + +from SCons.Script import DefaultEnvironment + +env = DefaultEnvironment() + +BOARD_OPTS = env.get("BOARD_OPTIONS", {}).get("build", {}) + +env.Replace( + PLATFORMFW_DIR=join("$PIOPACKAGES_DIR", "framework-mbed") +) + +MBED_VARIANTS = { + "stm32f3discovery": "DISCO_F303VC", + "stm32f4discovery": "DISCO_F407VG", + "stm32f429discovery": "DISCO_F429ZI", + "blueboard_lpc11u24": "LPC11U24", + "dipcortexm0": "LPC11U24", + "seeeduinoArchPro": "ARCH_PRO", + "ubloxc027": "UBLOX_C027", + "lpc1114fn28": "LPC1114", + "lpc11u35": "LPC11U35_401", + "mbuino": "LPC11U24", + "nrf51_mkit": "NRF51822", + "redBearLab": "NRF51822", + "nrf51-dt": "NRF51_DK", + "redBearLabBLENano": "NRF51822", + "wallBotBLE": "NRF51822", + "frdm_kl25z": "KL25Z", + "frdm_kl46z": "KL46Z", + "frdm_k64f": "K64F", + "frdm_kl05z": "KL05Z", + "frdm_k20d50m": "K20D50M", + "frdm_k22f": "K22F" +} + + +def parse_eix_file(filename): + result = {} + paths = ( + ("CFLAGS", "./Target/Source/CC/Switch"), + ("CXXFLAGS", "./Target/Source/CPPC/Switch"), + ("CPPDEFINES", "./Target/Source/Symbols/Symbol"), + ("FILES", "./Target/Files/File"), + ("LINKFLAGS", "./Target/Source/LD/Switch"), + ("STDLIBS", "./Target/Source/Syslibs/Library"), + ("LDSCRIPT_PATH", "./Target/Source/Scriptfile"), + ("CPPPATH", "./Target/Compiler/Includepaths/Includepath") + ) + + tree = ElementTree.parse(filename) + + for (key, path) in paths: + if key not in result: + result[key] = [] + + for node in tree.findall(path): + _nkeys = node.keys() + result[key].append( + node.get(_nkeys[0]) if len(_nkeys) == 1 else node.attrib) + + return result + + +def get_source_files(flist): + files = [] + for f in flist: + if f['type'] == "h" or not f['name'].startswith("mbed"): + continue + files.append(join("$BUILD_DIR", "FrameworkMBED", f['name'][5:])) + return files + + +def get_build_flags(data): + flags = {} + cflags = set(data.get("CFLAGS", [])) + cxxflags = set(data.get("CXXFLAGS", [])) + cppflags = set(cflags & cxxflags) + flags['CPPFLAGS'] = list(cppflags) + flags['CXXFLAGS'] = list(cxxflags - cppflags) + flags['CFLAGS'] = list(cflags - cppflags) + return flags + +board_type = env.subst("$BOARD") +variant = MBED_VARIANTS[ + board_type] if board_type in MBED_VARIANTS else board_type.upper() +eixdata = parse_eix_file( + join(env.subst("$PLATFORMFW_DIR"), "variant", variant, "%s.eix" % variant)) + +build_flags = get_build_flags(eixdata) +env.Replace( + CPPFLAGS=build_flags.get("CPPFLAGS", []), + CFLAGS=build_flags.get("CFLAGS", []), + CXXFLAGS=build_flags.get("CXXFLAGS", []), + LINKFLAGS=eixdata.get("LINKFLAGS", []), + CPPDEFINES=[define for define in eixdata.get("CPPDEFINES", [])], + LDSCRIPT_PATH=normpath(join( + "$PLATFORMFW_DIR", "core", eixdata.get("LDSCRIPT_PATH")[0][5:])) +) + +# Hook for K64F and K22F +if board_type in ("frdm_k22f", "frdm_k64f"): + env.Append( + LINKFLAGS=["-Wl,--start-group"] + ) + +for lib_path in eixdata.get("CPPPATH"): + _vdir = join("$BUILD_DIR", "FrameworkMbedInc%d" % crc32(lib_path)) + env.VariantDir( + _vdir, + join("$PLATFORMFW_DIR", "core", lib_path[5:]) + ) + env.Append(CPPPATH=[_vdir]) + + +# +# Target: Build MBED Library +# + +libs = [l for l in eixdata.get("STDLIBS", []) if l not in env.get("LIBS")] + +env.VariantDir( + join("$BUILD_DIR", "FrameworkMBED"), + join("$PLATFORMFW_DIR", "core") +) +libs.append(env.Library( + join("$BUILD_DIR", "FrameworkMBED"), + get_source_files(eixdata.get("FILES", [])) +)) + +env.Append(LIBS=libs) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 130fd22f..512615b6 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -7,7 +7,7 @@ from time import sleep from SCons.Script import Exit from serial import Serial -from platformio.util import get_serialports +from platformio.util import get_logicaldisks, get_serialports def FlushSerialBuffer(env, port): @@ -52,16 +52,28 @@ def WaitForNewSerialPort(_, before): def AutodetectUploadPort(env): - if "UPLOAD_PORT" not in env: + if "UPLOAD_PORT" in env: + return + + if env.subst("$FRAMEWORK") == "mbed": + for item in get_logicaldisks(): + if not item['name'] or "mbed" != item['name'].lower(): + continue + print "Auto-detected UPLOAD_PORT: %s" % item['disk'] + env.Replace(UPLOAD_PORT=item['disk']) + break + else: for item in get_serialports(): - if "VID:PID" in item['hwid']: - print "Auto-detected UPLOAD_PORT: %s" % item['port'] - env.Replace(UPLOAD_PORT=item['port']) - break + if "VID:PID" not in item['hwid']: + continue + print "Auto-detected UPLOAD_PORT: %s" % item['port'] + env.Replace(UPLOAD_PORT=item['port']) + break if "UPLOAD_PORT" not in env: Exit("Error: Please specify `upload_port` for environment or use " - "global `--upload-port` option.\n") + "global `--upload-port` option.\n" + "For the some development platforms it can be USB flash drive\n") def exists(_): diff --git a/platformio/util.py b/platformio/util.py index b4f0473c..9c1007b8 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -3,8 +3,10 @@ import json import os +import re import subprocess -from os.path import abspath, dirname, expanduser, isdir, isfile, join, realpath +from os.path import (abspath, basename, dirname, expanduser, isdir, isfile, + join, realpath) from platform import system, uname from threading import Thread @@ -173,7 +175,30 @@ def get_serialports(): from serial.tools.list_ports_posix import comports else: raise exception.GetSerialPortsError(os.name) - return[{"port": p, "description": d, "hwid": h} for p, d, h in comports()] + return [{"port": p, "description": d, "hwid": h} for p, d, h in comports()] + + +def get_logicaldisks(): + disks = [] + if system() == "Windows": + result = exec_command( + ["wmic", "logicaldisk", "get", "name,VolumeName"]).get("out") + disknamere = re.compile(r"^([A-Z]{1}\:)\s*(\S+)?") + for line in result.split("\n"): + match = disknamere.match(line.strip()) + if not match: + continue + disks.append({"disk": match.group(1), "name": match.group(2)}) + else: + result = exec_command(["df"]).get("out") + disknamere = re.compile(r"\d+\%\s+([a-z\d\-_/]+)$", flags=re.I) + for line in result.split("\n"): + match = disknamere.search(line.strip()) + if not match: + continue + disks.append({"disk": match.group(1), + "name": basename(match.group(1))}) + return disks def get_api_result(path, params=None, data=None): diff --git a/scripts/mbed_to_package.py b/scripts/mbed_to_package.py new file mode 100644 index 00000000..e56d0f05 --- /dev/null +++ b/scripts/mbed_to_package.py @@ -0,0 +1,64 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +from os import getcwd, mkdir, makedirs, listdir +from os.path import isfile, isdir, join +from shutil import copy2, rmtree, copytree +from sys import exit as sys_exit +from sys import path +import zipfile + + +MBED_DIR = "/home/valeros/mbed-master" +OUTPUT_DIR = "/home/valeros/mbed-framework" +CORE_DIR = join(OUTPUT_DIR, "core") +VARIANT_DIR = join(OUTPUT_DIR, "variant") + +path.append("..") +path.append(MBED_DIR) +from workspace_tools.export import gccarm +from platformio.util import exec_command + + +def _unzip_generated_file(mcu): + filename = join( + MBED_DIR, "build", "export", "MBED_A1_emblocks_%s.zip" % mcu) + variant_dir = join(VARIANT_DIR, mcu) + if isfile(filename): + print "Processing board: %s" % mcu + with zipfile.ZipFile(filename) as zfile: + mkdir(variant_dir) + file_data = zfile.read("MBED_A1/MBED_A1.eix") + with open(join(variant_dir, "%s.eix" % mcu), "w") as f: + f.write(file_data) + else: + print "Warning! Skipped board: %s" % mcu + + +def main(): + print "Starting..." + if isdir(OUTPUT_DIR): + rmtree(OUTPUT_DIR) + print "Delete previous framework dir" + makedirs(VARIANT_DIR) + # copy MBED library + mbedlib_dir = join(MBED_DIR, "libraries", "mbed") + for item in listdir(mbedlib_dir): + src = join(mbedlib_dir, item) + dst = join(CORE_DIR, item) + if isdir(src): + copytree(src, dst) + else: + copy2(src, dst) + # make .eix files + for mcu in set(gccarm.GccArm.TARGETS): + exec_command( + ["python", join(MBED_DIR, "workspace_tools", "project.py"), + "--mcu", mcu, "-i", "emblocks", "-p", "0"], cwd=getcwd() + ) + _unzip_generated_file(mcu) + print "Complete!" + + +if __name__ == "__main__": + sys_exit(main())