diff options
| author | Damien George <damien.p.george@gmail.com> | 2017-09-06 13:40:51 +1000 |
|---|---|---|
| committer | Damien George <damien.p.george@gmail.com> | 2017-09-06 13:40:51 +1000 |
| commit | 01dd7804b87d60b2deab16712eccb3b97351a9b7 (patch) | |
| tree | 1aa21f38a872b8e62a3d4e4f74f68033c6f827e4 /ports/zephyr | |
| parent | a9862b30068fc9df1022f08019fb35aaa5085f64 (diff) | |
ports: Make new ports/ sub-directory and move all ports there.
This is to keep the top-level directory clean, to make it clear what is
core and what is a port, and to allow the repository to grow with new ports
in a sustainable way.
Diffstat (limited to 'ports/zephyr')
30 files changed, 1918 insertions, 0 deletions
diff --git a/ports/zephyr/.gitignore b/ports/zephyr/.gitignore new file mode 100644 index 000000000..00ca089d1 --- /dev/null +++ b/ports/zephyr/.gitignore @@ -0,0 +1 @@ +outdir/ diff --git a/ports/zephyr/Kbuild b/ports/zephyr/Kbuild new file mode 100644 index 000000000..9e656d5f4 --- /dev/null +++ b/ports/zephyr/Kbuild @@ -0,0 +1,3 @@ +#subdir-ccflags-y += -I$(SOURCE_DIR)/../mylib/include + +obj-y += src/ diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile new file mode 100644 index 000000000..5840cc47e --- /dev/null +++ b/ports/zephyr/Makefile @@ -0,0 +1,105 @@ +# +# This is the main Makefile, which uses MicroPython build system, +# but Zephyr arch-specific toolchain and target-specific flags. +# This Makefile builds MicroPython as a library, and then calls +# recursively Makefile.zephyr to build complete application binary +# using Zephyr build system. +# +# To build a "minimal" configuration, use "make-minimal" wrapper. + +BOARD ?= qemu_x86 +CONF_FILE = prj_$(BOARD)_merged.conf +OUTDIR_PREFIX = $(BOARD) + +# Default heap size is 16KB, which is on conservative side, to let +# it build for smaller boards, but it won't be enough for larger +# applications, and will need to be increased. +MICROPY_HEAP_SIZE = 16384 +FROZEN_DIR = scripts + +# Default target +all: + +# Zephyr (generated) config files - must be defined before include below +Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export +ifneq ($(MAKECMDGOALS), clean) +include $(Z_EXPORTS) +endif + +include ../py/mkenv.mk +include $(TOP)/py/py.mk + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(ZEPHYR_BASE)/net/ip +INC += -I$(ZEPHYR_BASE)/net/ip/contiki +INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os + +SRC_C = main.c \ + help.c \ + modusocket.c \ + modutime.c \ + modzephyr.c \ + modmachine.c \ + machine_pin.c \ + uart_core.c \ + lib/utils/stdout_helpers.c \ + lib/utils/printf.c \ + lib/utils/pyexec.c \ + lib/utils/interrupt_char.c \ + lib/mp-readline/readline.c \ + $(SRC_MOD) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \ + -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) + +include $(TOP)/py/mkrules.mk + +# We use single target here ($(Z_EXPORTS)) for simplicity, but actually +# number of things get generated here: 'initconfig' generates C header for +# Kconfig configuration, 'outputexports' generates make environment with CC, +# etc., and 'lib' generates other headers which may be included by zephyr.h, +# e.g. DTS-related. +$(Z_EXPORTS): $(CONF_FILE) + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports lib + +GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver +KCONFIG_TARGETS = \ + initconfig config nconfig menuconfig xconfig gconfig \ + oldconfig silentoldconfig defconfig savedefconfig \ + allnoconfig allyesconfig alldefconfig randconfig \ + listnewconfig olddefconfig +CLEAN_TARGETS = pristine mrproper + +$(GENERIC_TARGETS): $(LIBMICROPYTHON) +$(CLEAN_TARGETS): clean + +$(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) $@ + +$(LIBMICROPYTHON): | $(Z_EXPORTS) +build/genhdr/qstr.i.last: | $(Z_EXPORTS) + +# If we recreate libmicropython, also cause zephyr.bin relink +LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk + +# MicroPython's global clean cleans everything, fast +CLEAN_EXTRA = outdir + +# Clean Zephyr things in Zephyr way +z_clean: + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean + +# This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which +# can be overriden +prj_$(BOARD)_merged.conf: prj_base.conf prj_$(BOARD).conf + $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ + +test: + cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../zephyr run BOARD=$(BOARD) QEMU_PTY=1" diff --git a/ports/zephyr/Makefile.zephyr b/ports/zephyr/Makefile.zephyr new file mode 100644 index 000000000..16f0a9452 --- /dev/null +++ b/ports/zephyr/Makefile.zephyr @@ -0,0 +1,30 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +KERNEL_TYPE = micro +# BOARD must be passed on command line from main Makefile +#BOARD = +CONF_FILE = prj.conf +QEMU_NET = 1 + +#export SOURCE_DIR = $(ZEPHYR_BASE)/samples/static_lib/hello_world +export LDFLAGS_zephyr += -L$(CURDIR) +export ALL_LIBS += micropython + +include ${ZEPHYR_BASE}/Makefile.inc +ifeq ($(QEMU_NET), 1) +include ${ZEPHYR_BASE}/samples/net/common/Makefile.ipstack +endif diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md new file mode 100644 index 000000000..018b4ce71 --- /dev/null +++ b/ports/zephyr/README.md @@ -0,0 +1,113 @@ +MicroPython port to Zephyr RTOS +=============================== + +This is an work-in-progress port of MicroPython to Zephyr RTOS +(http://zephyrproject.org). + +This port requires Zephyr version 1.8 or higher. All boards supported +by Zephyr (with standard level of features support, like UART console) +should work with MicroPython (but not all were tested). + +Features supported at this time: + +* REPL (interactive prompt) over Zephyr UART console. +* `utime` module for time measurements and delays. +* `machine.Pin` class for GPIO control. +* `usocket` module for networking (IPv4/IPv6). +* "Frozen modules" support to allow to bundle Python modules together + with firmware. Including complete applications, including with + run-on-boot capability. + +Over time, bindings for various Zephyr subsystems may be added. + + +Building +-------- + +Follow to Zephyr web site for Getting Started instruction of installing +Zephyr SDK, getting Zephyr source code, and setting up development +environment. (Direct link: +https://www.zephyrproject.org/doc/getting_started/getting_started.html). +You may want to build Zephyr's own sample applications to make sure your +setup is correct. + +To build MicroPython port, in the port subdirectory (zephyr/), run: + + make BOARD=<board> + +If you don't specify BOARD, the default is `qemu_x86` (x86 target running +in QEMU emulator). Consult Zephyr documentation above for the list of +supported boards. + + +Running +------- + +To run the resulting firmware in QEMU (for BOARDs like qemu_x86, +qemu_cortex_m3): + + make qemu + +With the default configuration, networking is now enabled, so you need to +follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu +to setup host side of TAP/SLIP networking. If you get error like: + + could not connect serial device to character backend 'unix:/tmp/slip.sock' + +it's a sign that you didn't followed instructions above. If you would like +to just run it quickly without extra setup, see "minimal" build below. + +For deploying/flashing a firmware on a real board, follow Zephyr +documentation for a given board, including known issues for that board +(if any). (Mind again that networking is enabled for the default build, +so you should know if there're any special requirements in that regard, +cf. for example QEMU networking requirements above; real hardware boards +generally should not have any special requirements, unless there're known +issues). + + +Quick example +------------- + +To blink an LED: + + import time + from machine import Pin + + LED = Pin(("GPIO_1", 21), Pin.OUT) + while True: + LED.value(1) + time.sleep(0.5) + LED.value(0) + time.sleep(0.5) + +The above code uses an LED location for a FRDM-K64F board (port B, pin 21; +following Zephyr conventions port are identified by "GPIO_x", where *x* +starts from 0). You will need to adjust it for another board (using board's +reference materials). To execute the above sample, copy it to clipboard, in +MicroPython REPL enter "paste mode" using Ctrl+E, paste clipboard, press +Ctrl+D to finish paste mode and start execution. + + +Minimal build +------------- + +MicroPython is committed to maintain minimal binary size for Zephyr port +below 128KB, as long as Zephyr project is committed to maintain stable +minimal size of their kernel (which they appear to be). Note that at such +size, there is no support for any Zephyr features beyond REPL over UART, +and only very minimal set of builtin Python modules is available. Thus, +this build is more suitable for code size control and quick demonstrations +on smaller systems. It's also suitable for careful enabling of features +one by one to achieve needed functionality and code size. This is in the +contrast to the "default" build, which may get more and more features +enabled over time. + +To make a minimal build: + + ./make-minimal BOARD=<board> + +To run a minimal build in QEMU without requiring TAP networking setup +run the following after you built image with the previous command: + + ./make-minimal BOARD=<qemu_x86|qemu_cortex_m3> qemu diff --git a/ports/zephyr/help.c b/ports/zephyr/help.c new file mode 100644 index 000000000..0c7f27940 --- /dev/null +++ b/ports/zephyr/help.c @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char *zephyr_help_text = +"Welcome to MicroPython!\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; diff --git a/ports/zephyr/machine_pin.c b/ports/zephyr/machine_pin.c new file mode 100644 index 000000000..c23ac08f0 --- /dev/null +++ b/ports/zephyr/machine_pin.c @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include <zephyr.h> +#include <gpio.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "modmachine.h" + +const mp_obj_base_t machine_pin_obj_template = {&machine_pin_type}; + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "<Pin %p %d>", self->port, self->pin); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get io mode + uint mode = args[ARG_mode].u_int; + + // get pull mode + uint pull = GPIO_PUD_NORMAL; + if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + } + + int ret = gpio_pin_configure(self->port, self->pin, mode | pull); + if (ret) { + mp_raise_ValueError("invalid pin"); + } + + // get initial value + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[ARG_value].u_obj)); + } + + return mp_const_none; +} + +// constructor(drv_name, pin, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted port + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + mp_raise_ValueError("Pin id must be tuple of (\"GPIO_x\", pin#)"); + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[0], 2, &items); + const char *drv_name = mp_obj_str_get_str(items[0]); + int wanted_pin = mp_obj_get_int(items[1]); + struct device *wanted_port = device_get_binding(drv_name); + if (!wanted_port) { + mp_raise_ValueError("invalid port"); + } + + machine_pin_obj_t *pin = m_new_obj(machine_pin_obj_t); + pin->base = machine_pin_obj_template; + pin->port = wanted_port; + pin->pin = wanted_pin; + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + u32_t pin_val; + (void)gpio_pin_read(self->port, self->pin, &pin_val); + return MP_OBJ_NEW_SMALL_INT(pin_val); + } else { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off); + +STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on); + +STATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + u32_t pin_val; + gpio_pin_read(self->port, self->pin, &pin_val); + return pin_val; + } + case MP_PIN_WRITE: { + gpio_pin_write(self->port, self->pin, arg); + return 0; + } + } + return -1; +} + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DIR_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DIR_OUT) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PUD_PULL_UP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PUD_PULL_DOWN) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t machine_pin_pin_p = { + .ioctl = machine_pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &machine_pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c new file mode 100644 index 000000000..a4301629f --- /dev/null +++ b/ports/zephyr/main.c @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <zephyr.h> +#ifdef CONFIG_NETWORKING +#include <net/net_context.h> +#endif + +#include "py/nlr.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/stackctrl.h" +#include "lib/utils/pyexec.h" +#include "lib/mp-readline/readline.h" + +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + +static char *stack_top; +static char heap[MICROPY_HEAP_SIZE]; + +void init_zephyr(void) { + // TODO: Make addresses configurable + #ifdef CONFIG_NETWORKING + if (net_if_get_default() == NULL) { + // If there's no default networking interface, + // there's nothing to configure. + return; + } + #endif + #ifdef CONFIG_NET_IPV4 + static struct in_addr in4addr_my = {{{192, 0, 2, 1}}}; + net_if_ipv4_addr_add(net_if_get_default(), &in4addr_my, NET_ADDR_MANUAL, 0); + static struct in_addr in4netmask_my = {{{255, 255, 255, 0}}}; + net_if_ipv4_set_netmask(net_if_get_default(), &in4netmask_my); + static struct in_addr in4gw_my = {{{192, 0, 2, 2}}}; + net_if_ipv4_set_gw(net_if_get_default(), &in4gw_my); + #endif + #ifdef CONFIG_NET_IPV6 + // 2001:db8::1 + static struct in6_addr in6addr_my = {{{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; + net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, NET_ADDR_MANUAL, 0); + #endif +} + +int real_main(void) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + mp_stack_set_top(stack_top); + // Make MicroPython's stack limit somewhat smaller than full stack available + mp_stack_set_limit(CONFIG_MAIN_STACK_SIZE - 512); + + init_zephyr(); + +soft_reset: + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_init(mp_sys_argv, 0); + + #if MICROPY_MODULE_FROZEN + pyexec_frozen_module("main.py"); + #endif + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + printf("soft reboot\n"); + goto soft_reset; + + return 0; +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + void *dummy; + gc_collect_start(); + gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_end(); + //gc_dump_info(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +NORETURN void nlr_jump_fail(void *val) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/ports/zephyr/make-minimal b/ports/zephyr/make-minimal new file mode 100755 index 000000000..1fc143e4d --- /dev/null +++ b/ports/zephyr/make-minimal @@ -0,0 +1,16 @@ +#!/bin/sh +# +# This is a wrapper for make to build a "minimal" Zephyr port. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-minimal BOARD=qemu_cortex_m3 +# ./make-minimal BOARD=qemu_cortex_m3 run +# + +make \ + CONF_FILE=prj_minimal.conf \ + CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_minimal.h>"' \ + FROZEN_DIR= \ + QEMU_NET=0 \ + "$@" diff --git a/ports/zephyr/makeprj.py b/ports/zephyr/makeprj.py new file mode 100644 index 000000000..239c877cd --- /dev/null +++ b/ports/zephyr/makeprj.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import sys +import os +import hashlib + + +def hash_file(fname): + if not os.path.exists(fname): + return b"" + hasher = hashlib.md5() + with open(fname, "rb") as f: + hasher.update(f.read()) + return hasher.digest() + + +old_digest = hash_file(sys.argv[3]) + +with open(sys.argv[3] + ".tmp", "wb") as f: + f.write(open(sys.argv[1], "rb").read()) + if os.path.exists(sys.argv[2]): + f.write(open(sys.argv[2], "rb").read()) + +new_digest = hash_file(sys.argv[3] + ".tmp") + +if new_digest != old_digest: + print("Replacing") + os.rename(sys.argv[3] + ".tmp", sys.argv[3]) +else: + os.remove(sys.argv[3] + ".tmp") diff --git a/ports/zephyr/modmachine.c b/ports/zephyr/modmachine.c new file mode 100644 index 000000000..5909c37d6 --- /dev/null +++ b/ports/zephyr/modmachine.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <misc/reboot.h> + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "modmachine.h" + +#if MICROPY_PY_MACHINE + +STATIC mp_obj_t machine_reset(void) { + sys_reboot(SYS_REBOOT_COLD); + // Won't get here, Zephyr has infiniloop on its side + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_reset_cause(void) { + printf("Warning: %s is not implemented\n", __func__); + return MP_OBJ_NEW_SMALL_INT(42); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + #ifdef CONFIG_REBOOT + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + + // reset causes + /*{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },*/ +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/ports/zephyr/modmachine.h b/ports/zephyr/modmachine.h new file mode 100644 index 000000000..84e4d10a8 --- /dev/null +++ b/ports/zephyr/modmachine.h @@ -0,0 +1,16 @@ +#ifndef MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H +#define MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pin_type; + +MP_DECLARE_CONST_FUN_OBJ_0(machine_info_obj); + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + struct device *port; + uint32_t pin; +} machine_pin_obj_t; + +#endif // MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c new file mode 100644 index 000000000..e021c3a44 --- /dev/null +++ b/ports/zephyr/modusocket.c @@ -0,0 +1,457 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#ifdef MICROPY_PY_USOCKET + +#include "py/runtime.h" +#include "py/stream.h" + +#include <stdio.h> +#include <zephyr.h> +// Zephyr's generated version header +#include <version.h> +#include <net/net_context.h> +#include <net/net_pkt.h> +#include <net/dns_resolve.h> +#ifdef CONFIG_NET_SOCKETS +#include <net/socket.h> +#endif + +#define DEBUG_PRINT 0 +#if DEBUG_PRINT // print debugging info +#define DEBUG_printf printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +typedef struct _socket_obj_t { + mp_obj_base_t base; + int ctx; + + #define STATE_NEW 0 + #define STATE_CONNECTING 1 + #define STATE_CONNECTED 2 + #define STATE_PEER_CLOSED 3 + int8_t state; +} socket_obj_t; + +STATIC const mp_obj_type_t socket_type; + +// Helper functions + +#define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } +#define RAISE_SOCK_ERRNO(x) { if ((int)(x) == -1) mp_raise_OSError(errno); } + +STATIC void socket_check_closed(socket_obj_t *socket) { + if (socket->ctx == -1) { + // already closed + mp_raise_OSError(EBADF); + } +} + +STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct sockaddr *sockaddr) { + // We employ the fact that port and address offsets are the same for IPv4 & IPv6 + struct sockaddr_in *sockaddr_in = (struct sockaddr_in*)sockaddr; + + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); + sockaddr_in->sin_family = net_context_get_family((void*)socket->ctx); + RAISE_ERRNO(net_addr_pton(sockaddr_in->sin_family, mp_obj_str_get_str(addr_items[0]), &sockaddr_in->sin_addr)); + sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1])); +} + +STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { + // We employ the fact that port and address offsets are the same for IPv4 & IPv6 + struct sockaddr_in6 *sockaddr_in6 = (struct sockaddr_in6*)addr; + char buf[40]; + net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); + mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); + + tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false); + // We employ the fact that port offset is the same for IPv4 & IPv6 + // not filled in + //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); + tuple->items[1] = port; + + if (addr->sa_family == AF_INET6) { + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); // flow_info + tuple->items[3] = MP_OBJ_NEW_SMALL_INT(sockaddr_in6->sin6_scope_id); + } + + return MP_OBJ_FROM_PTR(tuple); +} + +socket_obj_t *socket_new(void) { + socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t); + socket->base.type = (mp_obj_t)&socket_type; + socket->state = STATE_NEW; + return socket; +} + +// Methods + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + socket_obj_t *self = self_in; + if (self->ctx == -1) { + mp_printf(print, "<socket NULL>"); + } else { + struct net_context *ctx = (void*)self->ctx; + mp_printf(print, "<socket %p type=%d>", ctx, net_context_get_type(ctx)); + } +} + +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + socket_obj_t *socket = socket_new(); + + int family = AF_INET; + int socktype = SOCK_STREAM; + int proto = -1; + + if (n_args >= 1) { + family = mp_obj_get_int(args[0]); + if (n_args >= 2) { + socktype = mp_obj_get_int(args[1]); + if (n_args >= 3) { + proto = mp_obj_get_int(args[2]); + } + } + } + + if (proto == -1) { + proto = IPPROTO_TCP; + if (socktype != SOCK_STREAM) { + proto = IPPROTO_UDP; + } + } + + socket->ctx = zsock_socket(family, socktype, proto); + RAISE_SOCK_ERRNO(socket->ctx); + + return MP_OBJ_FROM_PTR(socket); +} + +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + parse_inet_addr(socket, addr_in, &sockaddr); + + int res = zsock_bind(socket->ctx, &sockaddr, sizeof(sockaddr)); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + parse_inet_addr(socket, addr_in, &sockaddr); + + int res = zsock_connect(socket->ctx, &sockaddr, sizeof(sockaddr)); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + mp_int_t backlog = mp_obj_get_int(backlog_in); + int res = zsock_listen(socket->ctx, backlog); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + socklen_t addrlen = sizeof(sockaddr); + int ctx = zsock_accept(socket->ctx, &sockaddr, &addrlen); + + socket_obj_t *socket2 = socket_new(); + socket2->ctx = ctx; + + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = MP_OBJ_FROM_PTR(socket2); + // TODO + client->items[1] = mp_const_none; + + return MP_OBJ_FROM_PTR(client); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *socket = self_in; + if (socket->ctx == -1) { + // already closed + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + ssize_t len = zsock_send(socket->ctx, buf, size, 0); + if (len == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + + return len; +} + +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int err = 0; + mp_uint_t len = sock_write(self_in, bufinfo.buf, bufinfo.len, &err); + if (len == MP_STREAM_ERROR) { + mp_raise_OSError(err); + } + return mp_obj_new_int_from_uint(len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *errcode) { + socket_obj_t *socket = self_in; + if (socket->ctx == -1) { + // already closed + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + ssize_t recv_len = zsock_recv(socket->ctx, buf, max_len, 0); + if (recv_len == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + + return recv_len; +} + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mp_int_t max_len = mp_obj_get_int(len_in); + vstr_t vstr; + // +1 to accommodate for trailing \0 + vstr_init_len(&vstr, max_len + 1); + + int err; + mp_uint_t len = sock_read(self_in, vstr.buf, max_len, &err); + + if (len == MP_STREAM_ERROR) { + vstr_clear(&vstr); + mp_raise_OSError(err); + } + + if (len == 0) { + vstr_clear(&vstr); + return mp_const_empty_bytes; + } + + vstr.len = len; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + mp_warning("setsockopt() not implemented"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + +STATIC mp_obj_t socket_close(mp_obj_t self_in) { + socket_obj_t *socket = self_in; + if (socket->ctx != -1) { + int res = zsock_close(socket->ctx); + RAISE_SOCK_ERRNO(res); + socket->ctx = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +STATIC const mp_stream_p_t socket_stream_p = { + .read = sock_read, + .write = sock_write, + //.ioctl = sock_ioctl, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .print = socket_print, + .make_new = socket_make_new, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +// +// getaddrinfo() implementation +// + +typedef struct _getaddrinfo_state_t { + mp_obj_t result; + struct k_sem sem; + mp_obj_t port; + int status; +} getaddrinfo_state_t; + +void dns_resolve_cb(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { + getaddrinfo_state_t *state = user_data; + DEBUG_printf("dns status: %d\n", status); + + if (info == NULL) { + if (status == DNS_EAI_ALLDONE) { + status = 0; + } + state->status = status; + k_sem_give(&state->sem); + return; + } + + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(info->ai_family); + // info->ai_socktype not filled + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM); + // info->ai_protocol not filled + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = format_inet_addr(&info->ai_addr, state->port); + mp_obj_list_append(state->result, MP_OBJ_FROM_PTR(tuple)); +} + +STATIC mp_obj_t mod_getaddrinfo(size_t n_args, const mp_obj_t *args) { + mp_obj_t host_in = args[0], port_in = args[1]; + const char *host = mp_obj_str_get_str(host_in); + mp_int_t family = 0; + if (n_args > 2) { + family = mp_obj_get_int(args[2]); + } + + getaddrinfo_state_t state; + // Just validate that it's int + (void)mp_obj_get_int(port_in); + state.port = port_in; + state.result = mp_obj_new_list(0, NULL); + k_sem_init(&state.sem, 0, UINT_MAX); + + for (int i = 2; i--;) { + int type = (family != AF_INET6 ? DNS_QUERY_TYPE_A : DNS_QUERY_TYPE_AAAA); + RAISE_ERRNO(dns_get_addr_info(host, type, NULL, dns_resolve_cb, &state, 3000)); + k_sem_take(&state.sem, K_FOREVER); + if (family != 0) { + break; + } + family = AF_INET6; + } + + // Raise error only if there's nothing to return, otherwise + // it may be IPv4 vs IPv6 differences. + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(state.result)); + if (state.status != 0 && len == 0) { + mp_raise_OSError(state.status); + } + + return state.result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_getaddrinfo_obj, 2, 3, mod_getaddrinfo); + + +STATIC mp_obj_t pkt_get_info(void) { + struct k_mem_slab *rx, *tx; + struct net_buf_pool *rx_data, *tx_data; + net_pkt_get_info(&rx, &tx, &rx_data, &tx_data); + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(rx)); + t->items[1] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(tx)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(rx_data->avail_count); + t->items[3] = MP_OBJ_NEW_SMALL_INT(tx_data->avail_count); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pkt_get_info_obj, pkt_get_info); + +STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + // objects + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, + + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(2) }, + + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_getaddrinfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_pkt_get_info), MP_ROM_PTR(&pkt_get_info_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; + +#endif // MICROPY_PY_USOCKET diff --git a/ports/zephyr/modutime.c b/ports/zephyr/modutime.c new file mode 100644 index 000000000..a5d32fe66 --- /dev/null +++ b/ports/zephyr/modutime.c @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME + +#include <zephyr.h> + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t mod_time_time(void) { + /* The absence of FP support is deliberate. The Zephyr port uses + * single precision floats so the fraction component will start to + * lose precision on devices with a long uptime. + */ + return mp_obj_new_int(k_uptime_get() / 1000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_UTIME diff --git a/ports/zephyr/modzephyr.c b/ports/zephyr/modzephyr.c new file mode 100644 index 000000000..265fc882d --- /dev/null +++ b/ports/zephyr/modzephyr.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_ZEPHYR + +#include <zephyr.h> +#include <misc/stack.h> + +#include "py/runtime.h" + +STATIC mp_obj_t mod_is_preempt_thread(void) { + return mp_obj_new_bool(k_is_preempt_thread()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_is_preempt_thread_obj, mod_is_preempt_thread); + +STATIC mp_obj_t mod_current_tid(void) { + return MP_OBJ_NEW_SMALL_INT(k_current_get()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_current_tid_obj, mod_current_tid); + +STATIC mp_obj_t mod_stacks_analyze(void) { + k_call_stacks_analyze(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_stacks_analyze_obj, mod_stacks_analyze); + +#ifdef CONFIG_NET_SHELL + +//int net_shell_cmd_iface(int argc, char *argv[]); + +STATIC mp_obj_t mod_shell_net_iface(void) { + net_shell_cmd_iface(0, NULL); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_shell_net_iface_obj, mod_shell_net_iface); + +#endif // CONFIG_NET_SHELL + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr) }, + { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) }, + { MP_ROM_QSTR(MP_QSTR_current_tid), MP_ROM_PTR(&mod_current_tid_obj) }, + { MP_ROM_QSTR(MP_QSTR_stacks_analyze), MP_ROM_PTR(&mod_stacks_analyze_obj) }, + + #ifdef CONFIG_NET_SHELL + { MP_ROM_QSTR(MP_QSTR_shell_net_iface), MP_ROM_PTR(&mod_shell_net_iface_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_zephyr = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_ZEPHYR diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h new file mode 100644 index 000000000..7ff05f45a --- /dev/null +++ b/ports/zephyr/mpconfigport.h @@ -0,0 +1,145 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <alloca.h> + +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" +// Included here to get basic Zephyr environment (macros, etc.) +#include <zephyr.h> + +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif + +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT zephyr_help_text +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_PY_STRUCT (0) +#ifdef CONFIG_NETWORKING +// If we have networking, we likely want errno comfort +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_USOCKET (1) +#endif +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_ZEPHYR (1) +#define MICROPY_PY_SYS_MODULES (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#define MICROPY_PY_SYS_PLATFORM "zephyr" + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else +#define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else +#define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + +#define MICROPY_MODULE_FROZEN_STR (1) + +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; + +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_time; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_zephyr; + +#if MICROPY_PY_USOCKET +#define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, +#define MICROPY_PY_USOCKET_WEAK_DEF { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, +#else +#define MICROPY_PY_USOCKET_DEF +#define MICROPY_PY_USOCKET_WEAK_DEF +#endif + +#if MICROPY_PY_UTIME +#define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, +#else +#define MICROPY_PY_UTIME_DEF +#endif + +#if MICROPY_PY_ZEPHYR +#define MICROPY_PY_ZEPHYR_DEF { MP_ROM_QSTR(MP_QSTR_zephyr), MP_ROM_PTR(&mp_module_zephyr) }, +#else +#define MICROPY_PY_ZEPHYR_DEF +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ + MICROPY_PY_USOCKET_DEF \ + MICROPY_PY_UTIME_DEF \ + MICROPY_PY_ZEPHYR_DEF \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ + MICROPY_PY_USOCKET_WEAK_DEF \ + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + diff --git a/ports/zephyr/mpconfigport_minimal.h b/ports/zephyr/mpconfigport_minimal.h new file mode 100644 index 000000000..f0e57d756 --- /dev/null +++ b/ports/zephyr/mpconfigport_minimal.h @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <alloca.h> + +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" +// Included here to get basic Zephyr environment (macros, etc.) +#include <zephyr.h> + +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif + +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS_MODULES (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else +#define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else +#define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/ports/zephyr/mphalport.h b/ports/zephyr/mphalport.h new file mode 100644 index 000000000..e3cca8d37 --- /dev/null +++ b/ports/zephyr/mphalport.h @@ -0,0 +1,25 @@ +#include <zephyr.h> +#include "lib/utils/interrupt_char.h" + +static inline mp_uint_t mp_hal_ticks_us(void) { + return SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32()) / 1000; +} + +static inline mp_uint_t mp_hal_ticks_ms(void) { + return k_uptime_get(); +} + +static inline mp_uint_t mp_hal_ticks_cpu(void) { + // ticks_cpu() is defined as using the highest-resolution timing source + // in the system. This is usually a CPU clock, but doesn't have to be, + // here we just use Zephyr hi-res timer. + return k_cycle_get_32(); +} + +static inline void mp_hal_delay_us(mp_uint_t delay) { + k_busy_wait(delay); +} + +static inline void mp_hal_delay_ms(mp_uint_t delay) { + k_sleep(delay); +} diff --git a/ports/zephyr/prj_96b_carbon.conf b/ports/zephyr/prj_96b_carbon.conf new file mode 100644 index 000000000..40b57e69c --- /dev/null +++ b/ports/zephyr/prj_96b_carbon.conf @@ -0,0 +1,2 @@ +# TODO: Enable networking +CONFIG_NETWORKING=y diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf new file mode 100644 index 000000000..c3ba2812f --- /dev/null +++ b/ports/zephyr/prj_base.conf @@ -0,0 +1,42 @@ +CONFIG_LEGACY_KERNEL=n +CONFIG_REBOOT=y + +CONFIG_STDOUT_CONSOLE=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y +CONFIG_NEWLIB_LIBC=y +CONFIG_FLOAT=y +CONFIG_MAIN_STACK_SIZE=4096 + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_NBUF_RX_COUNT=5 + +# DNS +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2 +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="192.0.2.2" + +# Diagnostics and debugging + +# Required for zephyr.stack_analyze() +CONFIG_INIT_STACKS=y + +# Required for usocket.pkt_get_info() +CONFIG_NET_BUF_POOL_USAGE=y + +# Required for usocket.shell_*() +#CONFIG_NET_SHELL=y + +# Uncomment to enable "INFO" level net_buf logging +#CONFIG_NET_LOG=y +#CONFIG_NET_DEBUG_NET_BUF=y +# Change to 4 for "DEBUG" level +#CONFIG_SYS_LOG_NET_LEVEL=3 diff --git a/ports/zephyr/prj_frdm_k64f.conf b/ports/zephyr/prj_frdm_k64f.conf new file mode 100644 index 000000000..611d6bc0a --- /dev/null +++ b/ports/zephyr/prj_frdm_k64f.conf @@ -0,0 +1,2 @@ +# Networking drivers +CONFIG_NET_L2_ETHERNET=y diff --git a/ports/zephyr/prj_minimal.conf b/ports/zephyr/prj_minimal.conf new file mode 100644 index 000000000..5d6b353ba --- /dev/null +++ b/ports/zephyr/prj_minimal.conf @@ -0,0 +1,6 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y +CONFIG_NEWLIB_LIBC=y +CONFIG_FLOAT=y +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/ports/zephyr/prj_qemu_cortex_m3.conf b/ports/zephyr/prj_qemu_cortex_m3.conf new file mode 100644 index 000000000..09614c362 --- /dev/null +++ b/ports/zephyr/prj_qemu_cortex_m3.conf @@ -0,0 +1,3 @@ +# Networking drivers +# SLIP driver for QEMU +CONFIG_NET_SLIP_TAP=y diff --git a/ports/zephyr/prj_qemu_x86.conf b/ports/zephyr/prj_qemu_x86.conf new file mode 100644 index 000000000..ef60cfec9 --- /dev/null +++ b/ports/zephyr/prj_qemu_x86.conf @@ -0,0 +1,6 @@ +# Networking drivers +# SLIP driver for QEMU +CONFIG_NET_SLIP_TAP=y + +# Default RAM easily overflows with uPy and networking +CONFIG_RAM_SIZE=320 diff --git a/ports/zephyr/src/Makefile b/ports/zephyr/src/Makefile new file mode 100644 index 000000000..36dd8c64e --- /dev/null +++ b/ports/zephyr/src/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +obj-y += zephyr_start.o zephyr_getchar.o diff --git a/ports/zephyr/src/zephyr_getchar.c b/ports/zephyr/src/zephyr_getchar.c new file mode 100644 index 000000000..52b3394d0 --- /dev/null +++ b/ports/zephyr/src/zephyr_getchar.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Linaro + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <zephyr.h> +#include <uart.h> +#include <drivers/console/uart_console.h> +#include <misc/printk.h> +#include "zephyr_getchar.h" + +extern int mp_interrupt_char; +void mp_keyboard_interrupt(void); + +static struct k_sem uart_sem; +#define UART_BUFSIZE 256 +static uint8_t uart_ringbuf[UART_BUFSIZE]; +static uint8_t i_get, i_put; + +static int console_irq_input_hook(uint8_t ch) +{ + int i_next = (i_put + 1) & (UART_BUFSIZE - 1); + if (i_next == i_get) { + printk("UART buffer overflow - char dropped\n"); + return 1; + } + if (ch == mp_interrupt_char) { + mp_keyboard_interrupt(); + return 1; + } else { + uart_ringbuf[i_put] = ch; + i_put = i_next; + } + //printk("%x\n", ch); + k_sem_give(&uart_sem); + k_yield(); + return 1; +} + +uint8_t zephyr_getchar(void) { + k_sem_take(&uart_sem, K_FOREVER); + unsigned int key = irq_lock(); + uint8_t c = uart_ringbuf[i_get++]; + i_get &= UART_BUFSIZE - 1; + irq_unlock(key); + return c; +} + +void zephyr_getchar_init(void) { + k_sem_init(&uart_sem, 0, UINT_MAX); + uart_console_in_debug_hook_install(console_irq_input_hook); + // All NULLs because we're interested only in the callback above + uart_register_input(NULL, NULL, NULL); +} diff --git a/ports/zephyr/src/zephyr_getchar.h b/ports/zephyr/src/zephyr_getchar.h new file mode 100644 index 000000000..fb5f19a7b --- /dev/null +++ b/ports/zephyr/src/zephyr_getchar.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Linaro + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> + +void zephyr_getchar_init(void); +uint8_t zephyr_getchar(void); diff --git a/ports/zephyr/src/zephyr_start.c b/ports/zephyr/src/zephyr_start.c new file mode 100644 index 000000000..9e8a90beb --- /dev/null +++ b/ports/zephyr/src/zephyr_start.c @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <zephyr.h> +#include "zephyr_getchar.h" + +int real_main(void); + +void main(void) { + zephyr_getchar_init(); + real_main(); +} diff --git a/ports/zephyr/uart_core.c b/ports/zephyr/uart_core.c new file mode 100644 index 000000000..1e85053cd --- /dev/null +++ b/ports/zephyr/uart_core.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <unistd.h> +#include "py/mpconfig.h" +#include "src/zephyr_getchar.h" +// Zephyr headers +#include <uart.h> + +/* + * Core UART functions to implement for a port + */ + +// Receive single character +int mp_hal_stdin_rx_chr(void) { + return zephyr_getchar(); +} + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + static struct device *uart_console_dev; + if (uart_console_dev == NULL) { + uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME); + } + + while (len--) { + uart_poll_out(uart_console_dev, *str++); + } +} diff --git a/ports/zephyr/z_config.mk b/ports/zephyr/z_config.mk new file mode 100644 index 000000000..28addd8f2 --- /dev/null +++ b/ports/zephyr/z_config.mk @@ -0,0 +1,17 @@ +srctree = $(ZEPHYR_BASE) + +include $(Z_DOTCONFIG) +override ARCH = $(subst $(DQUOTE),,$(CONFIG_ARCH)) +SOC_NAME = $(subst $(DQUOTE),,$(CONFIG_SOC)) +SOC_SERIES = $(subst $(DQUOTE),,$(CONFIG_SOC_SERIES)) +SOC_FAMILY = $(subst $(DQUOTE),,$(CONFIG_SOC_FAMILY)) +ifeq ($(SOC_SERIES),) +SOC_PATH = $(SOC_NAME) +else +SOC_PATH = $(SOC_FAMILY)/$(SOC_SERIES) +endif + +KBUILD_CFLAGS := -c +include $(ZEPHYR_BASE)/scripts/Kbuild.include + +include $(ZEPHYR_BASE)/arch/$(ARCH)/Makefile |
