Compare commits

...

37 Commits

Author SHA1 Message Date
Daniel Thompson 32d4b1eb0f zephyr: Switch sub-makes to use proper environment variables
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2016-09-19 19:21:41 +01:00
Daniel Thompson 08d596dd95 zephyr: Use ?= for BOARD
The main zephyr build system allows BOARD to come from the environment
but the micropython pre-build does not. Fix this.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2016-09-19 19:20:48 +01:00
Daniel Thompson d6086be810 zephyr: Support extra make targets
The two variables, GENERIC_TARGETS and CONFIG_TARGETS come, respectively,
from the the lists shown during "make help" and "make kconfig-help".

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2016-09-19 19:20:21 +01:00
Daniel Thompson 9af5511d93 zephyr: Honour CONFIG_FP_HARD/SOFTABI build option
Currently micropython cannot be linked on some ARM platforms because
the micropython libraries and the OS code are compiled with different
float ABIs. This can be fixed by honouring the appropriate Kconfig
options.

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2016-09-19 19:18:02 +01:00
Daniel Thompson d5632b5292 zephyr: Automatically derive ARCH
Currently to compile for anything that except ARCH=x86 we have to
provide ARCH via the environment or make arguments. We can do better
than that!

Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2016-09-19 19:17:04 +01:00
Paul Sokolovsky 0ab6e8fbfd zephyr: Add mbedTLS config for the port.
Zephyr appear to include only constrained config, we need more features to
access real-world HTTPS, etc.
2016-09-19 00:43:24 +03:00
Paul Sokolovsky b6934ad68c zephyr: Bump heap size to 24K, as required for umqtt.simple. 2016-09-19 00:43:24 +03:00
Paul Sokolovsky 13d54f0914 zephyr: Enable ustruct module, required for umqtt.simple. 2016-09-19 00:43:24 +03:00
Paul Sokolovsky 668e5bcf41 zephyr/modsocket: socket_write: Send only data fitting in a netbuf. 2016-09-19 00:43:24 +03:00
Paul Sokolovsky 37c7951926 zephyr/modsocket: Detect connection reset in connect().
TODO: Think about connection reset in other places too.
2016-09-19 00:43:24 +03:00
Paul Sokolovsky 814d6e4169 zephyr: Enable frozen modules support. 2016-09-19 00:43:24 +03:00
Paul Sokolovsky 1819653ce9 zephyr: Enable building ussl_mbedtls module.
Using Zephyr's builtin mbedtls.
2016-09-19 00:43:24 +03:00
Paul Sokolovsky 90ed575cdc extmod/modussl_mbedtls: Use 2-component include paths.
This is required to use mbedTLS versions from various sources, e.g.
mainline vs embedded into Zephyr RTOS.
2016-09-19 00:43:24 +03:00
Paul Sokolovsky 508ed4cc64 extmod/modussl_mbedtls: Add server_hostname param for wrap_socket().
In CPython, module-level .wrap_socket() function actually doesn't accept
(or document) this param, only SSLContext.wrap_socket() has.
2016-09-19 00:43:23 +03:00
Paul Sokolovsky 2aa6cd9168 extmod/modussl_mbedtls: Implement key= and cert= args to wrap_socket().
Unlike standard keyfile= and certfile=, these accept byte buffer objects
(to not depend on FS implementation).
2016-09-19 00:43:23 +03:00
Paul Sokolovsky d545d6bb83 py/py.mk: Add support for building modussl_mbedtls. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky 632dfe9be3 extmod/modussl_mbedtls: Initial implementation of mbedTLS ussl module. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky c703fd0480 zephyr/prj.conf: Add network debug logging options (commented). 2016-09-19 00:43:23 +03:00
Paul Sokolovsky 7443422093 zephyr/prj.conf: Enable mbedTLS. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky 23ca7e2657 zephyr/modsocket: Add DEBUG_printf() logging. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky e2032582d7 zephyr/modsocket: socket_read: Handle zero-length packets.
Zephyr actually filters these out, and requires patching to let them thru.
And underlying uIP uses them to e.g. communicate changes in connection
state (like peer closed connection). Without this change (and associated
Zephyr patch), socket read requests may hang if peer close happened after
read request was issued.
2016-09-19 00:43:23 +03:00
Paul Sokolovsky dd766368e2 zephyr/modsocket: repr(): Dump even more internal socket info. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky 15845b708c zephyr/modsocket: Implement partial reads/writes. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky 788f6ed2e3 zephyr/modsocket: Initial implementation of stream protocol. 2016-09-19 00:43:23 +03:00
Paul Sokolovsky f2a4d1ad4e zephyr/Makefile: Add qemu-net target to run QEMU virtual networking. 2016-09-19 00:43:22 +03:00
Paul Sokolovsky efed2dd984 zephyr: Enable building of modsocket. 2016-09-19 00:43:22 +03:00
Paul Sokolovsky 316f42bdc1 zephyr/modsocket: Add initial implementation of usocket module. 2016-09-19 00:43:22 +03:00
Paul Sokolovsky 13257a9f11 zephyr: Enable (IPv4) networking support. 2016-09-19 00:43:22 +03:00
Paul Sokolovsky b310abc440 zephyr: Implement smart way to access Zephyr config variables.
For this, we first build Z part with libmicropython.a not existing. This
produces autoconf.h with all setiings, but eventually fails on linking
stage due to missing libmicropython.a. We then build MicroPython, which
now can access values in autoconf.h. Then we execute Z build again, which
now succeeds.
2016-09-19 00:43:22 +03:00
Paul Sokolovsky d01061a198 zephyr/Makefile: Switch to qemu_x86 by default.
As it supports QEMU virtual networking.
2016-09-19 00:43:22 +03:00
Paul Sokolovsky bb7fd43b04 zephyr: Switch to microkernel, required for network to work in background. 2016-09-19 00:43:22 +03:00
Paul Sokolovsky 24026ed17b zephyr: Enable stack checking and micropython.mem_info(). 2016-09-19 00:43:22 +03:00
Paul Sokolovsky de2203510e zephyr/prj.conf: Set main thread stack size to 4K.
An interpreted language needs good size of stack to do anything useful
(minimum can be set to a lower value of course).
2016-09-19 00:43:22 +03:00
Paul Sokolovsky b0a95fc00c zephyr: Add README. 2016-09-19 00:43:21 +03:00
Paul Sokolovsky 8004ee68ff zephyr: Add zephyr_getchar module to handle console input.
From https://github.com/pfalcon/zephyr_getchar .
2016-09-19 00:43:21 +03:00
Paul Sokolovsky 217035f23a zephyr: Initial Zephyr RTOS port, Zephyr part. 2016-09-19 00:43:21 +03:00
Paul Sokolovsky bec77172e7 zephyr: Initial Zephyr RTOS port, MicroPython part. 2016-09-19 00:43:21 +03:00
19 changed files with 3697 additions and 0 deletions

View File

@ -0,0 +1,293 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Paul Sokolovsky
*
* 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_USSL && MICROPY_SSL_MBEDTLS
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/stream.h"
// mbedtls_time_t
#include "mbedtls/platform.h"
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/pk.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
typedef struct _mp_obj_ssl_socket_t {
mp_obj_base_t base;
mp_obj_t sock;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
mbedtls_x509_crt cert;
mbedtls_pk_context pkey;
} mp_obj_ssl_socket_t;
struct ssl_args {
mp_arg_val_t key;
mp_arg_val_t cert;
mp_arg_val_t server_side;
mp_arg_val_t server_hostname;
};
STATIC const mp_obj_type_t ussl_socket_type;
static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
printf("DBG:%s:%04d: %s\n", file, line, str);
}
// TODO: FIXME!
int null_entropy_func(void *data, unsigned char *output, size_t len) {
// enjoy random bytes
return 0;
}
int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
int err;
int out_sz = sock_stream->write(sock, buf, len, &err);
if (out_sz == MP_STREAM_ERROR) {
return -err;
} else {
return out_sz;
}
}
int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
int err;
int out_sz = sock_stream->read(sock, buf, len, &err);
if (out_sz == MP_STREAM_ERROR) {
return -err;
} else {
return out_sz;
}
}
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
o->base.type = &ussl_socket_type;
int ret;
mbedtls_ssl_init(&o->ssl);
mbedtls_ssl_config_init(&o->conf);
mbedtls_x509_crt_init(&o->cacert);
mbedtls_x509_crt_init(&o->cert);
mbedtls_pk_init(&o->pkey);
mbedtls_ctr_drbg_init(&o->ctr_drbg);
// Debug level (0-4)
mbedtls_debug_set_threshold(0);
mbedtls_entropy_init(&o->entropy);
const byte seed[] = "upy";
ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed));
if (ret != 0) {
printf("ret=%d\n", ret);
assert(0);
}
ret = mbedtls_ssl_config_defaults(&o->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
assert(0);
}
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);
mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);
ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
if (ret != 0) {
assert(0);
}
if (args->server_hostname.u_obj != mp_const_none) {
const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
if (ret != 0) {
assert(0);
}
}
o->sock = sock;
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
if (args->key.u_obj != MP_OBJ_NULL) {
mp_uint_t key_len;
const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len);
// len should include terminating null
ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
assert(ret == 0);
mp_uint_t cert_len;
const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
// len should include terminating null
ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
assert(ret == 0);
ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
assert(ret == 0);
}
if (args->server_side.u_bool) {
assert(0);
} else {
while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
//assert(0);
printf("mbedtls_ssl_handshake error: -%x\n", -ret);
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EIO)));
}
}
}
return o;
}
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<_SSLSocket %p>", self);
}
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
int ret = mbedtls_ssl_read(&o->ssl, buf, size);
if (ret >= 0) {
return ret;
}
*errcode = ret;
return MP_STREAM_ERROR;
}
STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
int ret = mbedtls_ssl_write(&o->ssl, buf, size);
if (ret >= 0) {
return ret;
}
*errcode = ret;
return MP_STREAM_ERROR;
}
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
mbedtls_x509_crt_free(&self->cacert);
mbedtls_ssl_free(&self->ssl);
mbedtls_ssl_config_free(&self->conf);
mbedtls_ctr_drbg_free(&self->ctr_drbg);
mbedtls_entropy_free(&self->entropy);
mp_obj_t dest[2];
mp_load_method(self->sock, MP_QSTR_close, dest);
return mp_call_method_n_kw(0, 0, dest);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_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_close), MP_ROM_PTR(&socket_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
STATIC const mp_stream_p_t ussl_socket_stream_p = {
.read = socket_read,
.write = socket_write,
};
STATIC const mp_obj_type_t ussl_socket_type = {
{ &mp_type_type },
// Save on qstr's, reuse same as for module
.name = MP_QSTR_ussl,
.print = socket_print,
.getiter = NULL,
.iternext = NULL,
.protocol = &ussl_socket_stream_p,
.locals_dict = (void*)&ussl_socket_locals_dict,
};
STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// TODO: Implement more args
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
// TODO: Check that sock implements stream protocol
mp_obj_t sock = pos_args[0];
struct ssl_args args;
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
return MP_OBJ_FROM_PTR(socket_new(sock, &args));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
{ MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
const mp_obj_module_t mp_module_ussl = {
.base = { &mp_type_module },
.name = MP_QSTR_ussl,
.globals = (mp_obj_dict_t*)&mp_module_ssl_globals,
};
#endif // MICROPY_PY_USSL

View File

@ -24,6 +24,11 @@ CFLAGS_MOD += -DMICROPY_PY_USSL=1
ifeq ($(MICROPY_SSL_AXTLS),1)
CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I../lib/axtls/ssl -I../lib/axtls/crypto -I../lib/axtls/config
LDFLAGS_MOD += -Lbuild -laxtls
else ifeq ($(MICROPY_SSL_MBEDTLS),1)
# Can be overriden by ports which have "builtin" mbedTLS
MICROPY_SSL_MBEDTLS_INCLUDE ?= ../lib/mbedtls/include
CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE)
LDFLAGS_MOD += -L../lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto
endif
endif
@ -210,6 +215,7 @@ PY_O_BASENAME = \
../extmod/machine_i2c.o \
../extmod/machine_spi.o \
../extmod/modussl_axtls.o \
../extmod/modussl_mbedtls.o \
../extmod/modurandom.o \
../extmod/modwebsocket.o \
../extmod/modwebrepl.o \

View File

@ -29,6 +29,7 @@ MICROPY_PY_FFI = 1
# ussl module requires axtls
MICROPY_PY_USSL = 1
MICROPY_SSL_AXTLS = 1
MICROPY_SSL_MBEDTLS = 0
# jni module requires JVM/JNI
MICROPY_PY_JNI = 0

3
zephyr/Kbuild 100644
View File

@ -0,0 +1,3 @@
#subdir-ccflags-y += -I$(SOURCE_DIR)/../mylib/include
obj-y += src/

112
zephyr/Makefile 100644
View File

@ -0,0 +1,112 @@
#
# This is main Makefile, which uses MicroPython build system, but
# Zephyr arch-specific toolchain (setup by Zephyr's Makefile.toolchain.*).
# Unfortunately, it's currently not possible to get target (as in: specific
# board to run on) specific compile-time options from Zephyr, so these must
# be set (duplicated) in this Makefile. Currently, these configured for
# ARM Cortex-M3. This Makefile builds MicroPython as a library, and then
# calls recursively Makefile.zephyr to build complete application using
# Zephyr build system.
#
BOARD ?= qemu_x86
# Zephyr 1.5.0
OUTDIR_PREFIX =
# Zephyr 1.6.0
#OUTDIR_PREFIX = $(BOARD)
DOTCONFIG = outdir/$(OUTDIR_PREFIX)/.config
DQUOTE = "
# "
include $(DOTCONFIG)
override ARCH = $(subst $(DQUOTE),,$(CONFIG_ARCH))
MICROPY_PY_USSL = 1
MICROPY_SSL_MBEDTLS = 1
MICROPY_SSL_MBEDTLS_INCLUDE = $(ZEPHYR_BASE)/ext/lib/crypto/mbedtls/include
FROZEN_DIR = scripts
# Zephyr toolchain config is 2-pass, so included twice
include $(ZEPHYR_BASE)/scripts/Makefile.toolchain.$(ZEPHYR_GCC_VARIANT)
include $(ZEPHYR_BASE)/scripts/Makefile.toolchain.$(ZEPHYR_GCC_VARIANT)
CFLAGS_arm = -mthumb -mcpu=cortex-m3 -mabi=aapcs
ifeq ($(CONFIG_FLOAT), y)
ifeq ($(CONFIG_FP_SOFTABI), y)
CFLAGS_arm += -mfloat-abi=softfp -mfpu=fpv4-sp-d16
endif
ifeq ($(CONFIG_FP_HARDABI), y)
CFLAGS_arm += -mfloat-abi=hard -mfpu=fpv4-sp-d16
endif
endif
CFLAGS_x86 = -fno-asynchronous-unwind-tables -ffreestanding -fno-stack-protector \
-fno-omit-frame-pointer -mpreferred-stack-boundary=2 -mno-sse -march=pentium
CFLAGS_TARGET = $(CFLAGS_$(ARCH))
include ../py/mkenv.mk
include ../py/py.mk
INC += -I.
INC += -I..
INC += -I$(BUILD)
INC += -I$(ZEPHYR_BASE)/include -I$(ZEPHYR_BASE) \
-I$(ZEPHYR_BASE)/net/ip -I$(ZEPHYR_BASE)/net/ip/contiki -I$(ZEPHYR_BASE)/net/ip/contiki/os \
-Ioutdir/$(OUTDIR_PREFIX)/misc/generated/sysgen \
-I$(dir $(Z_AUTOCONF_H))
SRC_C = main.c \
uart_core.c \
modsocket.c \
lib/utils/stdout_helpers.c \
lib/utils/printf.c \
lib/utils/pyexec.c \
lib/mp-readline/readline.c \
lib/netutils/netutils.c \
$(BUILD)/frozen.c \
$(SRC_MOD)
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C)
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
COPT = -Os -DNDEBUG -fdata-sections -ffunction-sections
CFLAGS = -std=gnu99 $(TOOLCHAIN_CFLAGS) $(INC) $(CFLAGS_MOD) $(COPT) $(CFLAGS_TARGET)
include ../py/mkrules.mk
$(DOTCONFIG) :
$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) initconfig
GENERIC_TARGETS = all zephyr qemu qemugdb flash debug
KCONFIG_TARGETS = config nconfig menuconfig xconfig gconfig
$(GENERIC_TARGETS) $(KCONFIG_TARGETS): $(LIBMICROPYTHON)
$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) $@
# Note: doesn't rebuild binary, just runs qemu against it
qemu-net:
$(ZEPHYR_SDK_INSTALL_DIR)/sysroots/i686-pokysdk-linux/usr/bin/qemu-system-i386 -m 32 -cpu qemu32 \
-no-reboot -nographic -vga none -display none -net none -clock dynticks -no-acpi -balloon none \
-L $(ZEPHYR_SDK_INSTALL_DIR)/sysroots/i686-pokysdk-linux/usr/share/qemu \
-bios bios.bin -machine type=pc-0.14 -pidfile qemu.pid \
-serial mon:stdio -serial none -serial unix:/tmp/slip.sock \
-kernel outdir/$(OUTDIR_PREFIX)/zephyr.elf
# For GDB debugging with QEMU
#-s -S
Z_AUTOCONF_H = outdir/$(OUTDIR_PREFIX)/include/generated/autoconf.h
$(LIBMICROPYTHON): $(Z_AUTOCONF_H)
build/genhdr/qstr.i.last: $(Z_AUTOCONF_H)
$(Z_AUTOCONF_H):
rm -f $(LIBMICROPYTHON)
-$(MAKE) -f Makefile.zephyr BOARD=$(BOARD)
# Clean Zephyr things too
CLEAN_EXTRA = outdir

View File

@ -0,0 +1,33 @@
#
# 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
MDEF_FILE = prj.mdef
#export SOURCE_DIR = $(ZEPHYR_BASE)/samples/static_lib/hello_world
export LDFLAGS_zephyr += -L$(CURDIR)
export ALL_LIBS += micropython
# Need to reference dir with mbedTLS config. ZEPHYRINCLUDE doesn't work
# (gets completely overriden by Z). Using STDINCLUDE is definitely a
# hack, but it happens not to be overriden by Z.
#export ZEPHYRINCLUDE += -I$(CURDIR)/src
export STDINCLUDE += -I$(CURDIR)/src
include ${ZEPHYR_BASE}/Makefile.inc

22
zephyr/README 100644
View File

@ -0,0 +1,22 @@
This is initial proof of concept port of MicroPython to Zephyr RTOS
http://zephyrproject.org. It only integrates with Zephyr's console
subsystem so far.
Supported out of the box is Zephyr's armv7-m (Cortex-M3) architecture,
with qemu_cortex_m3 being a default target. Supporting others architectures
may require editing makefiles.
To build:
Intstall Zephyr SDK and Zephyr source from the link above. Configure
Zephyr environment as described in its instructions. Then:
make
To run in QEMU:
make qemu
To build for a real board (see link above for supported Cortex-M boards):
make BOARD=frdm_k64f

99
zephyr/main.c 100644
View File

@ -0,0 +1,99 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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"
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
printf("MemoryError: lexer could not allocate memory\n");
return;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 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[24 * 1024];
int real_main(void) {
int stack_dummy;
stack_top = (char*)&stack_dummy;
mp_stack_set_top(stack_top);
// Should be set to CONFIG_MAIN_STACK_SIZE in prj.conf minus fuzz factor
mp_stack_set_limit(3584);
#if MICROPY_ENABLE_GC
gc_init(heap, heap + sizeof(heap));
#endif
mp_init();
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_event_repl_init();
for (;;) {
int c = mp_hal_stdin_rx_chr();
if (pyexec_event_repl_process_char(c)) {
break;
}
}
#else
pyexec_friendly_repl();
#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
//do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
mp_deinit();
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) {
return NULL;
}
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);
void nlr_jump_fail(void *val) {
}
void NORETURN __fatal_error(const char *msg) {
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

309
zephyr/modsocket.c 100644
View File

@ -0,0 +1,309 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Paul Sokolovsky
*
* 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 1 // MICROPY_PY_
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include "py/nlr.h"
#include "py/obj.h"
#include "py/stream.h"
#include "lib/netutils/netutils.h"
// Zephyr includes
#include <zephyr.h>
#include <net/net_core.h>
#include <net/net_socket.h>
#include <net/ip_buf.h>
#define PACK_ALIAS_STRUCT __attribute__((__packed__,__may_alias__))
#include <net/ip/contiki/ip/uipaddr.h>
#if 1 // print debugging info
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
#define IPADDR {{192, 0, 2, 2}}
#define MY_IPADDR {IPADDR}
#define WAIT_TICKS TICKS_UNLIMITED
// These are uIP public interface variables wich specify this host address/netmask.
uip_ipaddr_t uip_hostaddr = IPADDR;
uip_ipaddr_t uip_netmask = { { 255, 255, 255, 0 } };
static struct net_addr my_addr = {
.family = AF_INET,
{ .in_addr = MY_IPADDR },
};
typedef struct _socket_obj_t {
mp_obj_base_t base;
struct net_context *sock;
struct net_addr peer_addr;
struct net_buf *incoming;
mp_uint_t recv_offset;
#define STATE_NEW 0
#define STATE_CONNECTING 1
#define STATE_CONNECTED 2
#define STATE_PEER_CLOSED 3
#define STATE_CLOSED 4
byte state;
} socket_obj_t;
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
socket_obj_t *self = self_in;
if (self->sock != NULL) {
struct uip_conn *uip_connr = net_context_get_internal_connection(self->sock);
mp_printf(print, "<socket %p: state=%d Zstatus=%d income=%p(@%d) uip_conn=%p",
self->sock,
self->state,
net_context_get_connection_status(self->sock),
self->incoming,
self->recv_offset,
uip_connr);
if (uip_connr != NULL) {
mp_printf(print, " uip_flags=%x uip_oustand=%d",
uip_connr->tcpstateflags,
uip_outstanding(uip_connr));
}
mp_printf(print, ">");
} else {
mp_printf(print, "<socket %p: state=%d>", self->sock, self->state);
}
}
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) {
assert(n_args == 0);
#if 0
// Net initialization on demand. Has been moved to main(), to let
// the app respond to pings imemdiately after startup.
if (net_init() < 0) {
printf("Error in net_init()\n");
return mp_const_none;
}
#endif
socket_obj_t *o = m_new_obj(socket_obj_t);
o->base.type = type;
// We don't know if this will be client or server socket, so it's
// instantiated lazily
o->sock = NULL;
o->incoming = NULL;
o->recv_offset = 0;
o->state = STATE_NEW;
return o;
}
STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
socket_obj_t *self = self_in;
// Get address
uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
DEBUG_printf("resolved: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
struct in_addr in4addr_peer = {{{ip[0], ip[1], ip[2], ip[3]}}};
self->peer_addr.in_addr = in4addr_peer;
self->peer_addr.family = AF_INET;
int proto = IPPROTO_TCP;
self->sock = net_context_get(proto, &self->peer_addr, port, &my_addr, 0);
int ret = net_context_tcp_init(self->sock, /*NULL,*/ NET_TCP_TYPE_CLIENT);
DEBUG_printf("net_context_tcp_init()=%d\n", ret);
// Blocking wait until actually connected
while (net_context_get_connection_status(self->sock) == -EINPROGRESS) {
DEBUG_printf("waiting to connect: %d\n", net_context_get_connection_status(self->sock));
task_sleep(sys_clock_ticks_per_sec / 10);
}
if (net_context_get_connection_status(self->sock) == -ECONNRESET) {
self->state = STATE_PEER_CLOSED;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ECONNRESET)));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
socket_obj_t *self = self_in;
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
struct net_buf *netbuf = ip_buf_get_tx(self->sock);
uint8_t *ptr = net_buf_add(netbuf, bufinfo.len);
memcpy(ptr, bufinfo.buf, bufinfo.len);
ip_buf_appdatalen(netbuf) = bufinfo.len;
int ret = net_send(netbuf);
return mp_obj_new_int(ret);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t len, int *errcode) {
DEBUG_printf("socket_write(%p, %p, %d)\n", self_in, buf, len);
socket_obj_t *self = self_in;
struct uip_conn *uip_connr = net_context_get_internal_connection(self->sock);
while (uip_outstanding(uip_connr)) {
DEBUG_printf("wait outstanding flush of %d bytes\n", uip_outstanding(uip_connr));
task_sleep(sys_clock_ticks_per_sec / 10);
}
struct net_buf *netbuf = ip_buf_get_tx(self->sock);
if (len > net_buf_tailroom(netbuf)) {
len = net_buf_tailroom(netbuf);
}
uint8_t *ptr = net_buf_add(netbuf, len);
memcpy(ptr, buf, len);
ip_buf_appdatalen(netbuf) = len;
int ret = net_send(netbuf);
if (ret >= 0) {
return len;
}
*errcode = ret;
return MP_STREAM_ERROR;
}
STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t len, int *errcode) {
socket_obj_t *self = self_in;
struct uip_conn *uip_connr = net_context_get_internal_connection(self->sock);
DEBUG_printf("socket_read(%p, %p, %d) conn_flags: %x\n", self_in, buf, len, uip_connr->tcpstateflags);
while (self->incoming == NULL) {
if (self->state == STATE_PEER_CLOSED || uip_connr->tcpstateflags == UIP_CLOSED) {
DEBUG_printf("socket_read: Returning EOF\n");
return 0;
}
DEBUG_printf("socket_read: calling net_receive\n");
self->incoming = net_receive(self->sock, WAIT_TICKS);
if (uip_closed(self->incoming)) {
DEBUG_printf("uip_closed() == true\n");
self->state = STATE_PEER_CLOSED;
}
if (ip_buf_appdatalen(self->incoming) == 0) {
// We may be passed 0-length packet to indicate peer closed
// condition (or by any other reason).
self->incoming = NULL;
}
}
mp_uint_t remaining = ip_buf_appdatalen(self->incoming) - self->recv_offset;
if (len > remaining) {
len = remaining;
}
memcpy(buf, ip_buf_appdata(self->incoming) + self->recv_offset, len);
remaining -= len;
if (remaining == 0) {
ip_buf_unref(self->incoming);
self->incoming = NULL;
self->recv_offset = 0;
} else {
self->recv_offset += len;
}
return len;
}
STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
socket_obj_t *self = self_in;
if (self->state == STATE_PEER_CLOSED) {
return mp_const_empty_bytes;
}
struct net_buf *buf = net_receive(self->sock, WAIT_TICKS);
mp_obj_t ret = mp_obj_new_bytes(ip_buf_appdata(buf), ip_buf_appdatalen(buf));
if (uip_closed(buf)) {
//printf("uip_closed() == true\n");
self->state = STATE_PEER_CLOSED;
}
ip_buf_unref(buf);
return ret;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
socket_obj_t *self = self_in;
net_context_put(self->sock);
self->sock = NULL;
self->state = STATE_CLOSED;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
};
STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
STATIC const mp_stream_p_t socket_stream_p = {
.read = socket_read,
.write = socket_write,
};
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,
};
STATIC const mp_map_elem_t machine_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&socket_type },
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
const mp_obj_module_t mp_module_socket = {
.base = { &mp_type_module },
.name = MP_QSTR_usocket,
.globals = (mp_obj_dict_t*)&machine_module_globals,
};
#endif // MICROPY_PY_

View File

@ -0,0 +1,58 @@
#include <alloca.h>
// 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_DEBUG_PRINTERS (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_REPL_AUTO_INDENT (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_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_STRUCT (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)
#define MICROPY_HW_BOARD_NAME "zephyr-generic"
#define MICROPY_HW_MCU_NAME "unknown-cpu"
#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 void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
#define BYTES_PER_WORD (sizeof(mp_int_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_socket;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_socket) }, \
// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles
#include "autoconf.h"

View File

@ -0,0 +1,2 @@
static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; }
static inline void mp_hal_set_interrupt_char(char c) {}

29
zephyr/prj.conf 100644
View File

@ -0,0 +1,29 @@
CONFIG_STDOUT_CONSOLE=y
CONFIG_CONSOLE_HANDLER=y
CONFIG_NEWLIB_LIBC=y
CONFIG_FLOAT=y
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_NETWORKING=y
CONFIG_NETWORKING_WITH_IPV4=y
CONFIG_NETWORKING_WITH_TCP=y
CONFIG_NETWORKING_WITH_LOOPBACK=y
CONFIG_NETWORKING_UART=y
CONFIG_NETWORKING_DEBUG_UART=y
CONFIG_IP_BUF_RX_SIZE=8
CONFIG_IP_BUF_TX_SIZE=5
CONFIG_NANO_TIMEOUTS=y
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_BUILTIN=y
CONFIG_MBEDTLS_CFG_FILE="mbedtls-config-upy.h"
CONFIG_RAM_SIZE=530
# Network debug logging
CONFIG_NETWORKING_WITH_LOGGING=y
#CONFIG_NETWORK_IP_STACK_DEBUG_CONTEXT=y
#CONFIG_NETWORK_IP_STACK_DEBUG_TCP_PSOCK=y
# Verbose net_buf-level logging
#CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF=y
#CONFIG_NET_BUF_DEBUG=y

5
zephyr/prj.mdef 100644
View File

@ -0,0 +1,5 @@
% Application : MicroPython
% TASK NAME PRIO ENTRY STACK GROUPS
% ==================================
TASK MAIN 7 main 4096 [EXE]

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* 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"
static struct nano_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(struct device *dev, 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;
}
uart_ringbuf[i_put] = ch;
i_put = i_next;
//printk("%x\n", ch);
nano_isr_sem_give(&uart_sem);
return 1;
}
uint8_t zephyr_getchar(void) {
nano_task_sem_take(&uart_sem, TICKS_UNLIMITED);
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) {
nano_sem_init(&uart_sem);
struct device *uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
uart_irq_input_hook_set(uart_console_dev, console_irq_input_hook);
// All NULLs because we're interested only in the callback above
uart_register_input(NULL, NULL, NULL);
}

View File

@ -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);

View File

@ -0,0 +1,21 @@
#include <zephyr.h>
#include "zephyr_getchar.h"
int real_main(void);
void main(void) {
if (net_init() < 0) {
printf("Error in net_init()\n");
}
zephyr_getchar_init();
real_main();
}
// This gets pulled in when mbedTLS is enabled in Zephyr config.
// It doesn't seem to be used by mbedTLS directly directly, but
// rather pulled in for some other libc dependency. All in all,
// this doesn't seem to be called, so included to avoid link
// error.
int gettimeofday(struct timeval *tv, struct timezone *tz) {
printf("! dummy gettimeofday called\n");
}

22
zephyr/uart_core.c 100644
View File

@ -0,0 +1,22 @@
#include <unistd.h>
#include "py/mpconfig.h"
#include "src/zephyr_getchar.h"
// Stopgap
extern void printk(const char*, ...);
/*
* 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) {
while (len--) {
printk("%c", *str++);
}
}