├── env.sh ├── .west └── config ├── dat ├── fat12.dat └── img_magic.dat ├── Kbuild ├── doc └── images │ └── degu_logo.png ├── tool_env.sh ├── .gitmodules ├── .gitignore ├── version.h.in ├── make-minimal ├── Kconfig ├── z_config.mk ├── tools ├── imgtool │ ├── __init__.py │ ├── keys │ │ ├── general.py │ │ ├── rsa.py │ │ ├── __init__.py │ │ ├── ecdsa_test.py │ │ ├── rsa_test.py │ │ └── ecdsa.py │ ├── version.py │ ├── main.py │ └── image.py └── imgtool.py ├── src ├── Makefile ├── zephyr_getchar.h ├── power.c ├── zephyr_getchar.c └── zephyr_start.c ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── makeprj.py ├── mphalport.h ├── make-bin-testsuite ├── README.md ├── Makefile.zephyr ├── modmachine.h ├── degu_ota.h ├── degu_utils.h ├── degu_pm.h ├── prj_base.conf ├── mpconfigport_bin_testsuite.h ├── CMakeLists.txt ├── root-rsa-2048.pem ├── help.c ├── make-factory-image.sh ├── zcoap.h ├── zephyr_env.sh ├── uart_core.c ├── modutime.c ├── modmachine.c ├── modzephyr.c ├── mpconfigport_minimal.h ├── degu_pm.c ├── moddegu.c ├── prj_degu_evk.conf ├── Makefile ├── machine_adc.c ├── modzsensor.c ├── mpconfigport.h ├── main.c ├── machine_i2c.c ├── machine_pin.c ├── zcoap.c ├── machine_uart.c ├── degu_utils.c ├── degu_ota.c └── modusocket.c /env.sh: -------------------------------------------------------------------------------- 1 | source ./zephyr_env.sh 2 | source ./tool_env.sh 3 | -------------------------------------------------------------------------------- /.west/config: -------------------------------------------------------------------------------- 1 | [manifest] 2 | path = zephyr 3 | [zephyr] 4 | base = zephyr 5 | -------------------------------------------------------------------------------- /dat/fat12.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-degu/degu/HEAD/dat/fat12.dat -------------------------------------------------------------------------------- /Kbuild: -------------------------------------------------------------------------------- 1 | #subdir-ccflags-y += -I$(SOURCE_DIR)/../mylib/include 2 | 3 | obj-y += src/ 4 | -------------------------------------------------------------------------------- /dat/img_magic.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-degu/degu/HEAD/dat/img_magic.dat -------------------------------------------------------------------------------- /doc/images/degu_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-degu/degu/HEAD/doc/images/degu_logo.png -------------------------------------------------------------------------------- /tool_env.sh: -------------------------------------------------------------------------------- 1 | export ZEPHYR_TOOLCHAIN_VARIANT=zephyr 2 | export ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "zephyr"] 2 | path = zephyr 3 | url = https://github.com/open-degu/zephyr.git 4 | [submodule "micropython"] 5 | path = micropython 6 | url = https://github.com/micropython/micropython.git 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.elf 4 | *.bin 5 | *.map 6 | *.hex 7 | *.dis 8 | *.exe 9 | 10 | build/ 11 | outdir/ 12 | prj_degu_evk_merged.conf 13 | 14 | GPATH 15 | GRTAGS 16 | GSYMS 17 | GTAGS 18 | 19 | *.pyc 20 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef _DEGU_VERSION_H 2 | #define _DEGU_VERSION_H 3 | 4 | #define VERSION_MAJOR "${DEGU_VERSION_MAJOR}" 5 | #define VERSION_MINOR "${DEGU_VERSION_MINOR}" 6 | #define VERSION_REVISION "${DEGU_VERSION_REVISION}" 7 | 8 | #endif // _DEGU_VERSION_H 9 | -------------------------------------------------------------------------------- /make-minimal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is a wrapper for make to build a "minimal" Zephyr port. 4 | # It should be run just like make (i.e. extra vars can be passed on the 5 | # command line, etc.), e.g.: 6 | # 7 | # ./make-minimal BOARD=qemu_cortex_m3 8 | # ./make-minimal BOARD=qemu_cortex_m3 run 9 | # 10 | 11 | make \ 12 | CONF_FILE=prj_minimal.conf \ 13 | CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ 14 | FROZEN_DIR= \ 15 | QEMU_NET=0 \ 16 | "$@" 17 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | config NRF5_POWER_MGMT_EXAMPLE 2 | bool 3 | default y 4 | select HAS_SYS_POWER_STATE_SLEEP_1 5 | select HAS_SYS_POWER_STATE_SLEEP_2 6 | select HAS_SYS_POWER_STATE_SLEEP_3 7 | select HAS_SYS_POWER_STATE_DEEP_SLEEP_1 8 | select HAS_SYS_POWER_STATE_DEEP_SLEEP_2 9 | select HAS_SYS_POWER_STATE_DEEP_SLEEP_3 10 | help 11 | Hidden option enabling LPS_1 and LPS_2 low power states. 12 | This is needed, as these states are implemented by this example. 13 | 14 | # Include Zephyr's Kconfig. 15 | source "$ZEPHYR_BASE/Kconfig" 16 | -------------------------------------------------------------------------------- /z_config.mk: -------------------------------------------------------------------------------- 1 | srctree = $(ZEPHYR_BASE) 2 | 3 | include $(Z_DOTCONFIG) 4 | override ARCH = $(subst $(DQUOTE),,$(CONFIG_ARCH)) 5 | SOC_NAME = $(subst $(DQUOTE),,$(CONFIG_SOC)) 6 | SOC_SERIES = $(subst $(DQUOTE),,$(CONFIG_SOC_SERIES)) 7 | SOC_FAMILY = $(subst $(DQUOTE),,$(CONFIG_SOC_FAMILY)) 8 | ifeq ($(SOC_SERIES),) 9 | SOC_PATH = $(SOC_NAME) 10 | else 11 | SOC_PATH = $(SOC_FAMILY)/$(SOC_SERIES) 12 | endif 13 | 14 | KBUILD_CFLAGS := -c 15 | include $(ZEPHYR_BASE)/scripts/Kbuild.include 16 | 17 | include $(ZEPHYR_BASE)/arch/$(ARCH)/Makefile 18 | -------------------------------------------------------------------------------- /tools/imgtool/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Linaro Limited 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Intel Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | obj-y += zephyr_start.o zephyr_getchar.o 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tools/imgtool.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | # Copyright 2017 Linaro Limited 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from imgtool import main 18 | 19 | if __name__ == '__main__': 20 | main.imgtool() 21 | -------------------------------------------------------------------------------- /src/zephyr_getchar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Linaro 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | void zephyr_getchar_init(void); 20 | uint8_t zephyr_getchar(void); 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Version(please complete the following information):** 27 | - DeguFirmware: [e.g. 0.9.1] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /makeprj.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import os 4 | import hashlib 5 | 6 | 7 | def hash_file(fname): 8 | if not os.path.exists(fname): 9 | return b"" 10 | hasher = hashlib.md5() 11 | with open(fname, "rb") as f: 12 | hasher.update(f.read()) 13 | return hasher.digest() 14 | 15 | 16 | old_digest = hash_file(sys.argv[3]) 17 | 18 | with open(sys.argv[3] + ".tmp", "wb") as f: 19 | f.write(open(sys.argv[1], "rb").read()) 20 | if os.path.exists(sys.argv[2]): 21 | f.write(open(sys.argv[2], "rb").read()) 22 | 23 | new_digest = hash_file(sys.argv[3] + ".tmp") 24 | 25 | if new_digest != old_digest: 26 | print("Replacing") 27 | os.rename(sys.argv[3] + ".tmp", sys.argv[3]) 28 | else: 29 | os.remove(sys.argv[3] + ".tmp") 30 | -------------------------------------------------------------------------------- /mphalport.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib/utils/interrupt_char.h" 3 | 4 | static inline mp_uint_t mp_hal_ticks_us(void) { 5 | return SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32()) / 1000; 6 | } 7 | 8 | static inline mp_uint_t mp_hal_ticks_ms(void) { 9 | return k_uptime_get(); 10 | } 11 | 12 | static inline mp_uint_t mp_hal_ticks_cpu(void) { 13 | // ticks_cpu() is defined as using the highest-resolution timing source 14 | // in the system. This is usually a CPU clock, but doesn't have to be, 15 | // here we just use Zephyr hi-res timer. 16 | return k_cycle_get_32(); 17 | } 18 | 19 | static inline void mp_hal_delay_us(mp_uint_t delay) { 20 | k_busy_wait(delay); 21 | } 22 | 23 | static inline void mp_hal_delay_ms(mp_uint_t delay) { 24 | k_sleep(delay); 25 | } 26 | -------------------------------------------------------------------------------- /make-bin-testsuite: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is a wrapper for make to build a binary with builtin testsuite. 4 | # It should be run just like make (i.e. extra vars can be passed on the 5 | # command line, etc.), e.g.: 6 | # 7 | # ./make-bin-testsuite BOARD=qemu_cortex_m3 8 | # ./make-bin-testsuite BOARD=qemu_cortex_m3 run 9 | # 10 | 11 | (cd ../../tests; ./run-tests --write-exp) 12 | (cd ../../tests; ./run-tests --list-tests --target=minimal \ 13 | -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \ 14 | -e /set -e frozenset -e complex -e const -e native -e viper \ 15 | -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \ 16 | | ../tools/tinytest-codegen.py --stdin) > bin-testsuite.c 17 | 18 | make \ 19 | CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DTEST=\"bin-testsuite.c\" -DNO_FORKING' \ 20 | "$@" 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Degu logo](doc/images/degu_logo.png)](https://open-degu.com) 2 | 3 | Degu 4 | ======== 5 | 6 | Degu is an open-source sensor device platform based on a low-power MCU and the Grove sensors connection interfaces. Degu runs on Zephyr OS and can connect to the Degu gateway by Openthread stacks. Besides, Degu has the MicroPython interpreter that allows you to make your application. 7 | 8 | Building 9 | -------- 10 | 11 | Before building the Degu firmware, install Zephyr SDK and set up the building environment according to the instruction on Zephyr Project Getting Started. 12 | 13 | https://docs.zephyrproject.org/latest/getting_started/installation_linux.html 14 | 15 | To build the Degu firmware, run the following command: 16 | 17 | ./build.sh 18 | 19 | Then, you will get the image of Degu firmware as degu.bin. 20 | 21 | See also 22 | -------- 23 | 24 | * For more information, please visit [the Degu website](https://open-degu.com/). 25 | 26 | * For technical resources, please visit [the Degu repositories on GitHub](https://github.com/open-degu/). 27 | -------------------------------------------------------------------------------- /Makefile.zephyr: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016 Intel Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | KERNEL_TYPE = micro 18 | # BOARD must be passed on command line from main Makefile 19 | #BOARD = 20 | CONF_FILE = prj.conf 21 | QEMU_NET = 1 22 | 23 | #export SOURCE_DIR = $(ZEPHYR_BASE)/samples/static_lib/hello_world 24 | export LDFLAGS_zephyr += -L$(CURDIR) 25 | export ALL_LIBS += micropython 26 | 27 | include ${ZEPHYR_BASE}/Makefile.inc 28 | ifeq ($(QEMU_NET), 1) 29 | include ${ZEPHYR_BASE}/samples/net/common/Makefile.ipstack 30 | endif 31 | -------------------------------------------------------------------------------- /modmachine.h: -------------------------------------------------------------------------------- 1 | #ifndef MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H 2 | #define MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H 3 | 4 | #include "py/obj.h" 5 | #include "uart.h" 6 | 7 | extern const mp_obj_type_t machine_pin_type; 8 | extern const mp_obj_type_t machine_adc_type; 9 | extern const mp_obj_type_t machine_i2c_type; 10 | extern const mp_obj_type_t machine_uart_type; 11 | 12 | MP_DECLARE_CONST_FUN_OBJ_0(machine_info_obj); 13 | 14 | typedef struct _machine_pin_obj_t { 15 | mp_obj_base_t base; 16 | struct device *port; 17 | uint32_t pin; 18 | } machine_pin_obj_t; 19 | 20 | typedef struct _machine_adc_obj_t { 21 | mp_obj_base_t base; 22 | struct device *dev; 23 | uint8_t adc_channel; 24 | struct adc_channel_cfg *cfg; 25 | u16_t buffer; 26 | } machine_adc_obj_t; 27 | 28 | typedef struct _machine_i2c_obj_t { 29 | mp_obj_base_t base; 30 | struct device *dev; 31 | uint8_t i2c_channel; 32 | struct i2c_channel_cfg *cfg; 33 | u16_t buffer; 34 | } machine_i2c_obj_t; 35 | 36 | typedef struct _machine_uart_obj_t { 37 | mp_obj_base_t base; 38 | struct device *dev; 39 | uint8_t uart_channel; 40 | struct uart_config cfg; 41 | } machine_uart_obj_t; 42 | 43 | #endif // MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H 44 | -------------------------------------------------------------------------------- /degu_ota.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #define DEGU_OTA_OK 1 26 | #define DEGU_OTA_ERR 0 27 | 28 | int update_init(void); 29 | int check_update(void); 30 | int do_update(void); 31 | -------------------------------------------------------------------------------- /degu_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | void get_eui64(char *eui64); 26 | int degu_coap_request(u8_t *path, u8_t method, u8_t *payload, void (*callback)(u8_t *, u16_t)); 27 | int degu_get_asset(void); 28 | -------------------------------------------------------------------------------- /tools/imgtool/keys/general.py: -------------------------------------------------------------------------------- 1 | """General key class.""" 2 | 3 | import sys 4 | 5 | AUTOGEN_MESSAGE = "/* Autogenerated by imgtool.py, do not edit. */" 6 | 7 | class KeyClass(object): 8 | def _public_emit(self, header, trailer, indent, file=sys.stdout, len_format=None): 9 | print(AUTOGEN_MESSAGE, file=file) 10 | print(header, end='', file=file) 11 | encoded = self.get_public_bytes() 12 | for count, b in enumerate(encoded): 13 | if count % 8 == 0: 14 | print("\n" + indent, end='', file=file) 15 | else: 16 | print(" ", end='', file=file) 17 | print("0x{:02x},".format(b), end='', file=file) 18 | print("\n" + trailer, file=file) 19 | if len_format is not None: 20 | print(len_format.format(len(encoded)), file=file) 21 | 22 | def emit_c(self, file=sys.stdout): 23 | self._public_emit( 24 | header="const unsigned char {}_pub_key[] = {{".format(self.shortname()), 25 | trailer="};", 26 | indent=" ", 27 | len_format="const unsigned int {}_pub_key_len = {{}};".format(self.shortname()), 28 | file=file) 29 | 30 | def emit_rust(self, file=sys.stdout): 31 | self._public_emit( 32 | header="static {}_PUB_KEY: &'static [u8] = &[".format(self.shortname().upper()), 33 | trailer="];", 34 | indent=" ", 35 | file=file) 36 | -------------------------------------------------------------------------------- /degu_pm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | 27 | void degu_ext_device_power(bool enable); 28 | void openthread_suspend(otInstance *aInstance); 29 | void openthread_resume(otInstance *aInstance, uint8_t aChannel, otLinkModeConfig aConfig); 30 | -------------------------------------------------------------------------------- /prj_base.conf: -------------------------------------------------------------------------------- 1 | CONFIG_BUILD_OUTPUT_BIN=y 2 | CONFIG_REBOOT=y 3 | 4 | CONFIG_STDOUT_CONSOLE=y 5 | CONFIG_CONSOLE_HANDLER=y 6 | CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y 7 | 8 | CONFIG_CONSOLE_SUBSYS=y 9 | CONFIG_CONSOLE_GETCHAR=y 10 | CONFIG_CONSOLE_GETCHAR_BUFSIZE=128 11 | CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128 12 | 13 | CONFIG_NEWLIB_LIBC=y 14 | CONFIG_FLOAT=y 15 | CONFIG_MAIN_STACK_SIZE=4736 16 | 17 | # Enable sensor subsystem (doesn't add code if not used). 18 | # Specific sensors should be enabled per-board. 19 | CONFIG_SENSOR=y 20 | 21 | # Networking config 22 | CONFIG_NETWORKING=y 23 | CONFIG_NET_IPV6=y 24 | CONFIG_NET_UDP=y 25 | CONFIG_NET_SOCKETS=y 26 | CONFIG_TEST_RANDOM_GENERATOR=y 27 | 28 | CONFIG_NET_CONFIG_SETTINGS=y 29 | CONFIG_NET_CONFIG_INIT_TIMEOUT=3 30 | CONFIG_NET_CONFIG_NEED_IPV6=y 31 | 32 | 33 | # DNS 34 | CONFIG_DNS_RESOLVER=y 35 | CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2 36 | CONFIG_DNS_SERVER_IP_ADDRESSES=y 37 | 38 | # DHCP configuration. Until DHCP address is assigned, 39 | # static configuration above is used instead. 40 | CONFIG_NET_DHCPV4=y 41 | 42 | # Diagnostics and debugging 43 | 44 | # Required for zephyr.stack_analyze() 45 | CONFIG_INIT_STACKS=y 46 | 47 | # Required for usocket.pkt_get_info() 48 | CONFIG_NET_BUF_POOL_USAGE=y 49 | 50 | # Required for usocket.shell_*() 51 | #CONFIG_NET_SHELL=y 52 | 53 | # Uncomment to enable "INFO" level net_buf logging 54 | #CONFIG_NET_LOG=y 55 | #CONFIG_NET_DEBUG_NET_BUF=y 56 | # Change to 4 for "DEBUG" level 57 | #CONFIG_SYS_LOG_NET_LEVEL=3 58 | -------------------------------------------------------------------------------- /mpconfigport_bin_testsuite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2017 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include "mpconfigport.h" 27 | 28 | #ifdef TEST 29 | #include "lib/upytesthelper/upytesthelper.h" 30 | #define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) 31 | #endif 32 | -------------------------------------------------------------------------------- /src/power.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Nordic Semiconductor ASA. 3 | * Copyright (c) 2019 Atmark Techno, Inc. 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include "../degu_pm.h" 10 | 11 | void device_power(bool enable) 12 | { 13 | if (enable) { 14 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 15 | sys_pm_resume_devices(); 16 | #endif 17 | #ifndef ROUTER_ONLY 18 | degu_ext_device_power(true); 19 | #endif 20 | } else { 21 | #ifndef ROUTER_ONLY 22 | degu_ext_device_power(false); 23 | #endif 24 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 25 | sys_pm_suspend_devices(); 26 | #endif 27 | } 28 | } 29 | 30 | void sys_pm_notify_power_state_entry(enum power_states state) 31 | { 32 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 33 | switch (state) { 34 | case SYS_POWER_STATE_SLEEP_2: 35 | device_power(false); 36 | k_cpu_idle(); 37 | break; 38 | 39 | case SYS_POWER_STATE_SLEEP_3: 40 | device_power(false); 41 | k_cpu_idle(); 42 | break; 43 | 44 | case SYS_POWER_STATE_DEEP_SLEEP_1: 45 | device_power(false); 46 | break; 47 | 48 | default: 49 | break; 50 | } 51 | #endif 52 | } 53 | 54 | void sys_pm_notify_power_state_exit(enum power_states state) 55 | { 56 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 57 | switch (state) { 58 | case SYS_POWER_STATE_SLEEP_2: 59 | device_power(true); 60 | break; 61 | 62 | case SYS_POWER_STATE_SLEEP_3: 63 | device_power(true); 64 | break; 65 | 66 | case SYS_POWER_STATE_DEEP_SLEEP_1: 67 | device_power(true); 68 | break; 69 | 70 | default: 71 | break; 72 | } 73 | #endif 74 | } 75 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | 3 | include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) 4 | project(NONE) 5 | 6 | 7 | set(DEGU_VERSION_MAJOR "1") 8 | set(DEGU_VERSION_MINOR "0") 9 | set(DEGU_VERSION_REVISION "0-rc1") 10 | configure_file("$ENV{ZEPHYR_BASE}/../version.h.in" "$ENV{ZEPHYR_BASE}/../version.h") 11 | 12 | target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c src/power.c) 13 | 14 | zephyr_include_directories( 15 | $ENV{ZEPHYR_BASE}/../modules/lib/se_hostlib/inc 16 | $ENV{ZEPHYR_BASE}/../modules/lib/se_hostlib/common 17 | $ENV{ZEPHYR_BASE}/../modules/lib/se_hostlib/platform 18 | $ENV{ZEPHYR_BASE}/../modules/lib/se_hostlib/wrapper 19 | ) 20 | 21 | add_definitions( 22 | -DNO_SECURE_CHANNEL_SUPPORT 23 | -DZEPHYR 24 | -DFTR_FILE_SYSTEM 25 | -DTGT_A71CH 26 | -DI2C 27 | -DMBEDTLS 28 | -DSCP_MODE=NO_C_MAC_NO_C_ENC_NO_R_MAC_NO_R_ENC 29 | ) 30 | 31 | add_library(libmicropython STATIC IMPORTED) 32 | set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) 33 | target_link_libraries(app PUBLIC libmicropython) 34 | 35 | zephyr_get_include_directories_for_lang_as_string(C includes) 36 | zephyr_get_system_include_directories_for_lang_as_string(C system_includes) 37 | zephyr_get_compile_definitions_for_lang_as_string(C definitions) 38 | zephyr_get_compile_options_for_lang_as_string(C options) 39 | 40 | add_custom_target( 41 | outputexports 42 | COMMAND echo CC="${CMAKE_C_COMPILER}" 43 | COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} 44 | VERBATIM 45 | USES_TERMINAL 46 | ) 47 | -------------------------------------------------------------------------------- /root-rsa-2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0QYIGhhELBjo+/33DaNPH7vuXvmq0ksY01rpbRiAGfnwnDQb 3 | y/O8dNtC54x/EFN+Q14NVyxE0WcIDw27XO7ss5nf4E2EC6p3QWDtFShJpwG0PBDm 4 | aYwvX6xBTZ5cFN/y+M89Hm/nW7q0qciIfkc8lMN3Z1RLqo04NcpiYX634RXbd3PU 5 | vntyIYlpJPv4ZW5kPsgO14XVXErkUw0v/7f98xM5gz+jrtIPp2qd+f64zvoqvq+4 6 | 4PqCN1T0PuEr0NMIWBj2XkzIiIExrV+wghfyimknI/Orhz6TGh3+6PgaJGZZ+Byr 7 | 3M5oG2ZkNez6DRGdr1w6p9FnxkfvsUssYuHRyQIDAQABAoIBAEahFCHFK1v/OtLT 8 | eSSZl0Xw2dYr5QXULFpWsOOVUMv2QdB2ZyIehQKziEL3nYPlwpd+82EOa16awwVb 9 | LYF0lnUFvLltV/4dJtjnqJTqnSCamc1mJIVrwiJA8XwJ07GWDuL2G//p7jJ3v05T 10 | nZOV/KmD9xfqSvshZun+LgolqHqcrAa1f4cmuP9C9oqenZryljyfj7piaIZGI0JR 11 | PrJJ5kImYJqRcMgKTyHP4L8nwQ4moMJr6zbfbWxxb5TC7KVZSQ9UKZZ+ZLuy/pkU 12 | Qe4G8XSE0r+R9u4JCg87I1vgHhn8WJSxVX027OVUq5HfOzg2skQBTcExph5V9B2b 13 | onNxd8UCgYEA/32PW+ZwRcdKXMj+QVkxXUd6xkXy7mTXPEaQuOLWZQgrSqAFH1l4 14 | 5/6d099KAJrjM6kR8pKXtz72IIyMHTPm332ghymjKvaEl2XP9sF+f6FmYURar4y6 15 | 8Zh3eivP86+Q/YzOGKwtRSziBMzrAfoIXgtwH8pwIPYLP3zBV4449ZsCgYEA0XC/ 16 | gu2ub5M6EXBnjq9K2d4LlTyAPsIbAcMSwkhOUH4YJFS22qXLYQUA9zM+DUyLCrl/ 17 | PKN2G0HQVgMb4DIbeHv8kXB5oGm5zfbWorWqOomXB3AsI7X8YDMtf/PsZV2amBei 18 | qVskmPJQV21qFyeOcHlT+dHuRb0O0un3dK8RHmsCgYEApDCH4dJ80osZoflVVJ/C 19 | VqTqJOOtFEFgBQ+AUCEPEQyn7aRaxmPUjJsXyKJVx3/ChV+g9hf5Qj1HJXHNVbMW 20 | KwhsEpDSmHimizlV5clBxzntNpMcCHdTaJHILo5bbMqmThugE0ELMsp+UgFzAeky 21 | WWXWX8fUOYqFff5prh/rQQMCgYBQQ8FhT+113Rp37HgDerJY5HvT6afMZV8sQbJC 22 | uqsotepSohShnsBeoihIlF7HgfoXVhepCYwNzh8ll3NrbEiS2BFnO4+hJmOKx3pi 23 | SPTAElLLCvYfiXL6+yII01ZZUpIYj5ZLCR7xbovTtZ7e2M4B1L2WFBoYp+eydO/c 24 | y+rnmQKBgCh0gfyBT/OKPkfKv+Bbt8HcoxgEj+TyH+vYdeTbP9ZSJ6y5utMbPg7z 25 | iLLbJ+9IcSwPCwJSmI+I0Om4xEp4ZblCrzAG7hWvG2NNzxQjmoOOrAANyTvJR/ap 26 | N+UkQA4WrMSKEYyBlRS/hR9Unz31vMc2k9Re0ukWhWh/QksQGDfJ 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /help.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2013-2016 Damien P. George 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "py/builtin.h" 28 | 29 | const char zephyr_help_text[] = 30 | "Welcome to MicroPython!\n" 31 | "\n" 32 | "Control commands:\n" 33 | " CTRL-A -- on a blank line, enter raw REPL mode\n" 34 | " CTRL-B -- on a blank line, enter normal REPL mode\n" 35 | " CTRL-C -- interrupt a running program\n" 36 | " CTRL-D -- on a blank line, do a soft reset of the board\n" 37 | " CTRL-E -- on a blank line, enter paste mode\n" 38 | "\n" 39 | "For further help on a specific object, type help(obj)\n" 40 | ; 41 | -------------------------------------------------------------------------------- /make-factory-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | MCUBOOT=$1 4 | DEGU=$2 5 | OUT=$3 6 | 7 | check_ret () 8 | { 9 | if [ $? -ne 0 ]; then 10 | echo "Stop." 11 | exit 1 12 | fi 13 | } 14 | 15 | usage () 16 | { 17 | echo "make-factory-image 18 | Usage: $0 bootloader firmware out 19 | 20 | Make binary image for factory as degu-factory-firmware.bin . 21 | 22 | args: 23 | bootloader - MCUboot binary (not .hex) 24 | firmware - Degu firmware binary (not .hex) 25 | out - Factory image output" 26 | } 27 | 28 | filesize () 29 | { 30 | wc -c $1 | awk '{print $1}' 31 | } 32 | 33 | pad () 34 | { 35 | REGION_SIZE=$1 36 | FILE=$2 37 | 38 | REGION_SIZE=`printf '%d' ${REGION_SIZE}` 39 | 40 | if [ -e ${FILE} ]; then 41 | FILE_SIZE=`filesize ${FILE}` 42 | PAD_SIZE=$(( REGION_SIZE - FILE_SIZE )) 43 | if [ ${PAD_SIZE} -lt 0 ]; then 44 | echo "Too large file:" ${FILE} 45 | return 1 46 | fi 47 | else 48 | PAD_SIZE=${REGION_SIZE} 49 | fi 50 | 51 | if [ "$3" = "magic" ]; then 52 | PAD_SIZE=$(( PAD_SIZE - 16 )) 53 | fi 54 | 55 | dd if=/dev/zero ibs=1 count=${PAD_SIZE} | tr "\000" "\377" > .pad 56 | if [ "$3" = "magic" ]; then 57 | cat .pad dat/img_magic.dat > .tmp 58 | mv .tmp .pad 59 | fi 60 | 61 | if [ -e ${FILE} ]; then 62 | cat ${FILE} .pad > .${FILE}.pad 63 | else 64 | cp .pad .${FILE}.pad 65 | fi 66 | 67 | rm .pad 68 | return 0 69 | } 70 | 71 | if [ $# -lt 3 ]; then 72 | usage 73 | exit 1 74 | fi 75 | 76 | case $1 in 77 | "-h" | "--help" ) 78 | usage 79 | return 1 80 | ;; 81 | * ) 82 | pad 0x14000 ${MCUBOOT} 83 | check_ret 84 | pad 0x6e000 ${DEGU} magic 85 | check_ret 86 | pad 0x6e000 slot1 87 | check_ret 88 | pad 0x8000 scratch 89 | check_ret 90 | 91 | cat .${MCUBOOT}.pad .${DEGU}.pad .slot1.pad .scratch.pad dat/fat12.dat > ${OUT} 92 | echo "Done." 93 | 94 | rm .*.pad 95 | ;; 96 | esac 97 | 98 | return 0 99 | -------------------------------------------------------------------------------- /zcoap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #define COAP_PORT 5683 26 | #define COAPS_PORT 5684 27 | #define MAX_COAP_MSG_LEN 1152 28 | #define BLOCK_WISE_TRANSFER_SIZE_GET 0x6e000 29 | #define COAP_TYPE_CON 0 //Confirmable 30 | #define COAP_TYPE_NCON 1 //non-Confirmable 31 | #define COAP_TYPE_ACK 2 //Acknowledgement 32 | #define COAP_TYPE_RST 3 //Reset 33 | #define COAP_FAILED_TO_RECEIVE_RESPONSE -1 34 | 35 | int zcoap_request_post(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block); 36 | int zcoap_request_put(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block); 37 | int zcoap_request_get(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block); 38 | int zcoap_request_delete(int sock, u8_t *path); 39 | -------------------------------------------------------------------------------- /tools/imgtool/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Linaro Limited 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | Semi Semantic Versioning 17 | 18 | Implements a subset of semantic versioning that is supportable by the image 19 | header. 20 | """ 21 | 22 | from collections import namedtuple 23 | import re 24 | 25 | SemiSemVersion = namedtuple('SemiSemVersion', ['major', 'minor', 'revision', 26 | 'build']) 27 | 28 | version_re = re.compile( 29 | r"""^([1-9]\d*|0)(\.([1-9]\d*|0)(\.([1-9]\d*|0)(\+([1-9]\d*|0))?)?)?$""") 30 | 31 | 32 | def decode_version(text): 33 | """Decode the version string, which should be of the form maj.min.rev+build 34 | """ 35 | m = version_re.match(text) 36 | if m: 37 | result = SemiSemVersion( 38 | int(m.group(1)) if m.group(1) else 0, 39 | int(m.group(3)) if m.group(3) else 0, 40 | int(m.group(5)) if m.group(5) else 0, 41 | int(m.group(7)) if m.group(7) else 0) 42 | return result 43 | else: 44 | msg = "Invalid version number, should be maj.min.rev+build with later " 45 | msg += "parts optional" 46 | raise ValueError(msg) 47 | 48 | 49 | if __name__ == '__main__': 50 | print(decode_version("1.2")) 51 | print(decode_version("1.0")) 52 | print(decode_version("0.0.2+75")) 53 | print(decode_version("0.0.0+00")) 54 | -------------------------------------------------------------------------------- /src/zephyr_getchar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Linaro 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "zephyr_getchar.h" 22 | 23 | extern int mp_interrupt_char; 24 | void mp_keyboard_interrupt(void); 25 | 26 | static struct k_sem uart_sem; 27 | #define UART_BUFSIZE 256 28 | static uint8_t uart_ringbuf[UART_BUFSIZE]; 29 | static uint8_t i_get, i_put; 30 | 31 | static int console_irq_input_hook(uint8_t ch) 32 | { 33 | int i_next = (i_put + 1) & (UART_BUFSIZE - 1); 34 | if (i_next == i_get) { 35 | printk("UART buffer overflow - char dropped\n"); 36 | return 1; 37 | } 38 | if (ch == mp_interrupt_char) { 39 | mp_keyboard_interrupt(); 40 | return 1; 41 | } else { 42 | uart_ringbuf[i_put] = ch; 43 | i_put = i_next; 44 | } 45 | //printk("%x\n", ch); 46 | k_sem_give(&uart_sem); 47 | k_yield(); 48 | return 1; 49 | } 50 | 51 | uint8_t zephyr_getchar(void) { 52 | k_sem_take(&uart_sem, K_FOREVER); 53 | unsigned int key = irq_lock(); 54 | uint8_t c = uart_ringbuf[i_get++]; 55 | i_get &= UART_BUFSIZE - 1; 56 | irq_unlock(key); 57 | return c; 58 | } 59 | 60 | void zephyr_getchar_init(void) { 61 | k_sem_init(&uart_sem, 0, UINT_MAX); 62 | uart_console_in_debug_hook_install(console_irq_input_hook); 63 | // All NULLs because we're interested only in the callback above 64 | uart_register_input(NULL, NULL, NULL); 65 | } 66 | -------------------------------------------------------------------------------- /zephyr_env.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Wind River Systems, Inc. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | 7 | # In zsh the value of $0 depends on the FUNCTION_ARGZERO option which is 8 | # set by default. FUNCTION_ARGZERO, when it is set, sets $0 temporarily 9 | # to the name of the function/script when executing a shell function or 10 | # sourcing a script. POSIX_ARGZERO option, when it is set, exposes the 11 | # original value of $0 in spite of the current FUNCTION_ARGZERO setting. 12 | # 13 | # Note: The version of zsh need to be 5.0.6 or above. Any versions below 14 | # 5.0.6 maybe encoutner errors when sourcing this script. 15 | if [ -n "$ZSH_VERSION" ]; then 16 | DIR="${(%):-%N}" 17 | if [ $options[posixargzero] != "on" ]; then 18 | setopt posixargzero 19 | NAME=$(basename -- "$0") 20 | setopt posixargzero 21 | else 22 | NAME=$(basename -- "$0") 23 | fi 24 | else 25 | DIR="${BASH_SOURCE[0]}" 26 | NAME=$(basename -- "$0") 27 | fi 28 | 29 | if [ "X$NAME" "==" "Xzephyr-env.sh" ]; then 30 | echo "Source this file (do NOT execute it!) to set the Zephyr Kernel environment." 31 | exit 32 | fi 33 | 34 | # You can further customize your environment by creating a bash script called 35 | # .zephyrrc in your home directory. It will be automatically 36 | # run (if it exists) by this script. 37 | 38 | if uname | grep -q "MINGW"; then 39 | win_build=1 40 | PWD_OPT="-W" 41 | else 42 | win_build=0 43 | PWD_OPT="" 44 | fi 45 | 46 | # identify OS source tree root directory 47 | export ZEPHYR_BASE=$(pwd ${PWD_OPT})/zephyr 48 | unset PWD_OPT 49 | 50 | scripts_path=${ZEPHYR_BASE}/scripts 51 | if [ "$win_build" -eq 1 ]; then 52 | scripts_path=$(echo "/$scripts_path" | sed 's/\\/\//g' | sed 's/://') 53 | fi 54 | unset win_build 55 | if ! echo "${PATH}" | grep -q "${scripts_path}"; then 56 | export PATH=${scripts_path}:${PATH} 57 | fi 58 | unset scripts_path 59 | 60 | # enable custom environment settings 61 | zephyr_answer_file=~/zephyr-env_install.bash 62 | [ -f ${zephyr_answer_file} ] && { 63 | echo "Warning: Please rename ~/zephyr-env_install.bash to ~/.zephyrrc"; 64 | . ${zephyr_answer_file}; 65 | } 66 | unset zephyr_answer_file 67 | zephyr_answer_file=~/.zephyrrc 68 | [ -f ${zephyr_answer_file} ] && . ${zephyr_answer_file}; 69 | unset zephyr_answer_file 70 | -------------------------------------------------------------------------------- /uart_core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2016 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include 27 | #include "py/mpconfig.h" 28 | #include "src/zephyr_getchar.h" 29 | // Zephyr headers 30 | #include 31 | #include 32 | 33 | /* 34 | * Core UART functions to implement for a port 35 | */ 36 | 37 | // Receive single character 38 | int mp_hal_stdin_rx_chr(void) { 39 | #ifdef CONFIG_CONSOLE_SUBSYS 40 | return console_getchar(); 41 | #else 42 | return zephyr_getchar(); 43 | #endif 44 | } 45 | 46 | // Send string of given length 47 | void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { 48 | #ifdef CONFIG_CONSOLE_SUBSYS 49 | while (len--) { 50 | char c = *str++; 51 | while (console_putchar(c) == -1) { 52 | k_sleep(1); 53 | } 54 | } 55 | #else 56 | static struct device *uart_console_dev; 57 | if (uart_console_dev == NULL) { 58 | uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME); 59 | } 60 | 61 | while (len--) { 62 | uart_poll_out(uart_console_dev, *str++); 63 | } 64 | #endif 65 | } 66 | -------------------------------------------------------------------------------- /modutime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2013, 2014 Damien P. George 7 | * Copyright (c) 2016 Linaro Limited 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "py/mpconfig.h" 29 | #if MICROPY_PY_UTIME 30 | 31 | #include 32 | 33 | #include "py/runtime.h" 34 | #include "py/smallint.h" 35 | #include "py/mphal.h" 36 | #include "extmod/utime_mphal.h" 37 | 38 | STATIC mp_obj_t mod_time_time(void) { 39 | /* The absence of FP support is deliberate. The Zephyr port uses 40 | * single precision floats so the fraction component will start to 41 | * lose precision on devices with a long uptime. 42 | */ 43 | return mp_obj_new_int(k_uptime_get() / 1000); 44 | } 45 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); 46 | 47 | STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { 48 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, 49 | { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, 50 | { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, 51 | { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, 52 | { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, 53 | { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, 54 | { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, 55 | { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, 56 | { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, 57 | { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, 58 | }; 59 | 60 | STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); 61 | 62 | const mp_obj_module_t mp_module_time = { 63 | .base = { &mp_type_module }, 64 | .globals = (mp_obj_dict_t*)&mp_module_time_globals, 65 | }; 66 | 67 | #endif // MICROPY_PY_UTIME 68 | -------------------------------------------------------------------------------- /tools/imgtool/keys/rsa.py: -------------------------------------------------------------------------------- 1 | """ 2 | RSA Key management 3 | """ 4 | 5 | from cryptography.hazmat.backends import default_backend 6 | from cryptography.hazmat.primitives import serialization 7 | from cryptography.hazmat.primitives.asymmetric import rsa 8 | from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1 9 | from cryptography.hazmat.primitives.hashes import SHA256 10 | 11 | from .general import KeyClass 12 | 13 | class RSAUsageError(Exception): 14 | pass 15 | 16 | class RSA2048Public(KeyClass): 17 | """The public key can only do a few operations""" 18 | def __init__(self, key): 19 | self.key = key 20 | 21 | def shortname(self): 22 | return "rsa" 23 | 24 | def _unsupported(self, name): 25 | raise RSAUsageError("Operation {} requires private key".format(name)) 26 | 27 | def _get_public(self): 28 | return self.key 29 | 30 | def get_public_bytes(self): 31 | # The key embedded into MCUboot is in PKCS1 format. 32 | return self._get_public().public_bytes( 33 | encoding=serialization.Encoding.DER, 34 | format=serialization.PublicFormat.PKCS1) 35 | 36 | def export_private(self, path, passwd=None): 37 | self._unsupported('export_private') 38 | 39 | def export_public(self, path): 40 | """Write the public key to the given file.""" 41 | pem = self._get_public().public_bytes( 42 | encoding=serialization.Encoding.PEM, 43 | format=serialization.PublicFormat.SubjectPublicKeyInfo) 44 | with open(path, 'wb') as f: 45 | f.write(pem) 46 | 47 | def sig_type(self): 48 | return "PKCS1_PSS_RSA2048_SHA256" 49 | 50 | def sig_tlv(self): 51 | return "RSA2048" 52 | 53 | def sig_len(self): 54 | return 256 55 | 56 | class RSA2048(RSA2048Public): 57 | """ 58 | Wrapper around an 2048-bit RSA key, with imgtool support. 59 | """ 60 | 61 | def __init__(self, key): 62 | """The key should be a private key from cryptography""" 63 | self.key = key 64 | 65 | @staticmethod 66 | def generate(): 67 | pk = rsa.generate_private_key( 68 | public_exponent=65537, 69 | key_size=2048, 70 | backend=default_backend()) 71 | return RSA2048(pk) 72 | 73 | def _get_public(self): 74 | return self.key.public_key() 75 | 76 | def export_private(self, path, passwd=None): 77 | """Write the private key to the given file, protecting it with the optional password.""" 78 | if passwd is None: 79 | enc = serialization.NoEncryption() 80 | else: 81 | enc = serialization.BestAvailableEncryption(passwd) 82 | pem = self.key.private_bytes( 83 | encoding=serialization.Encoding.PEM, 84 | format=serialization.PrivateFormat.PKCS8, 85 | encryption_algorithm=enc) 86 | with open(path, 'wb') as f: 87 | f.write(pem) 88 | 89 | def sign(self, payload): 90 | # The verification code only allows the salt length to be the 91 | # same as the hash length, 32. 92 | return self.key.sign( 93 | data=payload, 94 | padding=PSS(mgf=MGF1(SHA256()), salt_length=32), 95 | algorithm=SHA256()) 96 | -------------------------------------------------------------------------------- /tools/imgtool/keys/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Linaro Limited 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | Cryptographic key management for imgtool. 17 | """ 18 | 19 | from cryptography.hazmat.backends import default_backend 20 | from cryptography.hazmat.primitives import serialization 21 | from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey 22 | from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, EllipticCurvePublicKey 23 | 24 | from .rsa import RSA2048, RSA2048Public, RSAUsageError 25 | from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError 26 | 27 | class PasswordRequired(Exception): 28 | """Raised to indicate that the key is password protected, but a 29 | password was not specified.""" 30 | pass 31 | 32 | def load(path, passwd=None): 33 | """Try loading a key from the given path. Returns None if the password wasn't specified.""" 34 | with open(path, 'rb') as f: 35 | raw_pem = f.read() 36 | try: 37 | pk = serialization.load_pem_private_key( 38 | raw_pem, 39 | password=passwd, 40 | backend=default_backend()) 41 | # Unfortunately, the crypto library raises unhelpful exceptions, 42 | # so we have to look at the text. 43 | except TypeError as e: 44 | msg = str(e) 45 | if "private key is encrypted" in msg: 46 | return None 47 | raise e 48 | except ValueError: 49 | # This seems to happen if the key is a public key, let's try 50 | # loading it as a public key. 51 | pk = serialization.load_pem_public_key( 52 | raw_pem, 53 | backend=default_backend()) 54 | 55 | if isinstance(pk, RSAPrivateKey): 56 | if pk.key_size != 2048: 57 | raise Exception("Unsupported RSA key size: " + pk.key_size) 58 | return RSA2048(pk) 59 | elif isinstance(pk, RSAPublicKey): 60 | if pk.key_size != 2048: 61 | raise Exception("Unsupported RSA key size: " + pk.key_size) 62 | return RSA2048Public(pk) 63 | elif isinstance(pk, EllipticCurvePrivateKey): 64 | if pk.curve.name != 'secp256r1': 65 | raise Exception("Unsupported EC curve: " + pk.curve.name) 66 | if pk.key_size != 256: 67 | raise Exception("Unsupported EC size: " + pk.key_size) 68 | return ECDSA256P1(pk) 69 | elif isinstance(pk, EllipticCurvePublicKey): 70 | if pk.curve.name != 'secp256r1': 71 | raise Exception("Unsupported EC curve: " + pk.curve.name) 72 | if pk.key_size != 256: 73 | raise Exception("Unsupported EC size: " + pk.key_size) 74 | return ECDSA256P1Public(pk) 75 | else: 76 | raise Exception("Unknown key type: " + str(type(pk))) 77 | -------------------------------------------------------------------------------- /modmachine.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2013-2015 Damien P. George 7 | * Copyright (c) 2016 Paul Sokolovsky 8 | * Copyright (c) 2016 Linaro Limited 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "py/obj.h" 34 | #include "py/runtime.h" 35 | #include "extmod/machine_mem.h" 36 | #include "extmod/machine_signal.h" 37 | #include "extmod/machine_pulse.h" 38 | #include "extmod/machine_i2c.h" 39 | #include "modmachine.h" 40 | 41 | #if MICROPY_PY_MACHINE 42 | 43 | STATIC mp_obj_t machine_reset(void) { 44 | sys_reboot(SYS_REBOOT_COLD); 45 | // Won't get here, Zephyr has infiniloop on its side 46 | return mp_const_none; 47 | } 48 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); 49 | 50 | STATIC mp_obj_t machine_reset_cause(void) { 51 | printf("Warning: %s is not implemented\n", __func__); 52 | return MP_OBJ_NEW_SMALL_INT(42); 53 | } 54 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); 55 | 56 | STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { 57 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, 58 | #ifdef CONFIG_REBOOT 59 | { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, 60 | #endif 61 | { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, 62 | 63 | { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, 64 | { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, 65 | { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, 66 | { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, 67 | { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, 68 | 69 | // reset causes 70 | /*{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },*/ 71 | }; 72 | 73 | STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); 74 | 75 | const mp_obj_module_t mp_module_machine = { 76 | .base = { &mp_type_module }, 77 | .globals = (mp_obj_dict_t*)&machine_module_globals, 78 | }; 79 | 80 | #endif // MICROPY_PY_MACHINE 81 | -------------------------------------------------------------------------------- /tools/imgtool/keys/ecdsa_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for ECDSA keys 3 | """ 4 | 5 | import io 6 | import os.path 7 | import sys 8 | import tempfile 9 | import unittest 10 | 11 | from cryptography.exceptions import InvalidSignature 12 | from cryptography.hazmat.primitives.asymmetric import ec 13 | from cryptography.hazmat.primitives.hashes import SHA256 14 | 15 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) 16 | 17 | from imgtool.keys import load, ECDSA256P1, ECDSAUsageError 18 | 19 | class EcKeyGeneration(unittest.TestCase): 20 | 21 | def setUp(self): 22 | self.test_dir = tempfile.TemporaryDirectory() 23 | 24 | def tname(self, base): 25 | return os.path.join(self.test_dir.name, base) 26 | 27 | def tearDown(self): 28 | self.test_dir.cleanup() 29 | 30 | def test_keygen(self): 31 | name1 = self.tname("keygen.pem") 32 | k = ECDSA256P1.generate() 33 | k.export_private(name1, b'secret') 34 | 35 | self.assertIsNone(load(name1)) 36 | 37 | k2 = load(name1, b'secret') 38 | 39 | pubname = self.tname('keygen-pub.pem') 40 | k2.export_public(pubname) 41 | pk2 = load(pubname) 42 | 43 | # We should be able to export the public key from the loaded 44 | # public key, but not the private key. 45 | pk2.export_public(self.tname('keygen-pub2.pem')) 46 | self.assertRaises(ECDSAUsageError, 47 | pk2.export_private, self.tname('keygen-priv2.pem')) 48 | 49 | def test_emit(self): 50 | """Basic sanity check on the code emitters.""" 51 | k = ECDSA256P1.generate() 52 | 53 | ccode = io.StringIO() 54 | k.emit_c(ccode) 55 | self.assertIn("ecdsa_pub_key", ccode.getvalue()) 56 | self.assertIn("ecdsa_pub_key_len", ccode.getvalue()) 57 | 58 | rustcode = io.StringIO() 59 | k.emit_rust(rustcode) 60 | self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue()) 61 | 62 | def test_emit_pub(self): 63 | """Basic sanity check on the code emitters.""" 64 | pubname = self.tname("public.pem") 65 | k = ECDSA256P1.generate() 66 | k.export_public(pubname) 67 | 68 | k2 = load(pubname) 69 | 70 | ccode = io.StringIO() 71 | k2.emit_c(ccode) 72 | self.assertIn("ecdsa_pub_key", ccode.getvalue()) 73 | self.assertIn("ecdsa_pub_key_len", ccode.getvalue()) 74 | 75 | rustcode = io.StringIO() 76 | k2.emit_rust(rustcode) 77 | self.assertIn("ECDSA_PUB_KEY", rustcode.getvalue()) 78 | 79 | def test_sig(self): 80 | k = ECDSA256P1.generate() 81 | buf = b'This is the message' 82 | sig = k.raw_sign(buf) 83 | 84 | # The code doesn't have any verification, so verify this 85 | # manually. 86 | k.key.public_key().verify( 87 | signature=sig, 88 | data=buf, 89 | signature_algorithm=ec.ECDSA(SHA256())) 90 | 91 | # Modify the message to make sure the signature fails. 92 | self.assertRaises(InvalidSignature, 93 | k.key.public_key().verify, 94 | signature=sig, 95 | data=b'This is thE message', 96 | signature_algorithm=ec.ECDSA(SHA256())) 97 | 98 | if __name__ == '__main__': 99 | unittest.main() 100 | -------------------------------------------------------------------------------- /modzephyr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2017 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "py/mpconfig.h" 28 | #if MICROPY_PY_ZEPHYR 29 | 30 | #include 31 | #include 32 | 33 | #include "py/runtime.h" 34 | 35 | STATIC void mp_stack_dump(const struct k_thread *thread, void *user_data) { 36 | stack_analyze((char *)user_data, (char *)thread->stack_info.start, 37 | thread->stack_info.size); 38 | } 39 | 40 | STATIC mp_obj_t mod_is_preempt_thread(void) { 41 | return mp_obj_new_bool(k_is_preempt_thread()); 42 | } 43 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_is_preempt_thread_obj, mod_is_preempt_thread); 44 | 45 | STATIC mp_obj_t mod_current_tid(void) { 46 | return MP_OBJ_NEW_SMALL_INT(k_current_get()); 47 | } 48 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_current_tid_obj, mod_current_tid); 49 | 50 | STATIC mp_obj_t mod_stacks_analyze(void) { 51 | k_thread_foreach(mp_stack_dump, NULL); 52 | return mp_const_none; 53 | } 54 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_stacks_analyze_obj, mod_stacks_analyze); 55 | 56 | #ifdef CONFIG_NET_SHELL 57 | 58 | //int net_shell_cmd_iface(int argc, char *argv[]); 59 | 60 | STATIC mp_obj_t mod_shell_net_iface(void) { 61 | net_shell_cmd_iface(0, NULL); 62 | return mp_const_none; 63 | } 64 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_shell_net_iface_obj, mod_shell_net_iface); 65 | 66 | #endif // CONFIG_NET_SHELL 67 | 68 | STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { 69 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr) }, 70 | { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) }, 71 | { MP_ROM_QSTR(MP_QSTR_current_tid), MP_ROM_PTR(&mod_current_tid_obj) }, 72 | { MP_ROM_QSTR(MP_QSTR_stacks_analyze), MP_ROM_PTR(&mod_stacks_analyze_obj) }, 73 | 74 | #ifdef CONFIG_NET_SHELL 75 | { MP_ROM_QSTR(MP_QSTR_shell_net_iface), MP_ROM_PTR(&mod_shell_net_iface_obj) }, 76 | #endif 77 | }; 78 | 79 | STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); 80 | 81 | const mp_obj_module_t mp_module_zephyr = { 82 | .base = { &mp_type_module }, 83 | .globals = (mp_obj_dict_t*)&mp_module_time_globals, 84 | }; 85 | 86 | #endif // MICROPY_PY_ZEPHYR 87 | -------------------------------------------------------------------------------- /mpconfigport_minimal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2016 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include 27 | 28 | // Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles 29 | #include "autoconf.h" 30 | // Included here to get basic Zephyr environment (macros, etc.) 31 | #include 32 | 33 | // Usually passed from Makefile 34 | #ifndef MICROPY_HEAP_SIZE 35 | #define MICROPY_HEAP_SIZE (16 * 1024) 36 | #endif 37 | 38 | #define MICROPY_STACK_CHECK (1) 39 | #define MICROPY_ENABLE_GC (1) 40 | #define MICROPY_HELPER_REPL (1) 41 | #define MICROPY_REPL_AUTO_INDENT (1) 42 | #define MICROPY_KBD_EXCEPTION (1) 43 | #define MICROPY_CPYTHON_COMPAT (0) 44 | #define MICROPY_PY_ASYNC_AWAIT (0) 45 | #define MICROPY_PY_ATTRTUPLE (0) 46 | #define MICROPY_PY_BUILTINS_ENUMERATE (0) 47 | #define MICROPY_PY_BUILTINS_FILTER (0) 48 | #define MICROPY_PY_BUILTINS_MIN_MAX (0) 49 | #define MICROPY_PY_BUILTINS_PROPERTY (0) 50 | #define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) 51 | #define MICROPY_PY_BUILTINS_REVERSED (0) 52 | #define MICROPY_PY_BUILTINS_SET (0) 53 | #define MICROPY_PY_BUILTINS_SLICE (0) 54 | #define MICROPY_PY_ARRAY (0) 55 | #define MICROPY_PY_COLLECTIONS (0) 56 | #define MICROPY_PY_CMATH (0) 57 | #define MICROPY_PY_IO (0) 58 | #define MICROPY_PY_STRUCT (0) 59 | #define MICROPY_PY_SYS_MODULES (0) 60 | #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) 61 | #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) 62 | #define MICROPY_PY_BUILTINS_COMPLEX (0) 63 | 64 | // Saving extra crumbs to make sure binary fits in 128K 65 | #define MICROPY_COMP_CONST_FOLDING (0) 66 | #define MICROPY_COMP_CONST (0) 67 | #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) 68 | 69 | #ifdef CONFIG_BOARD 70 | #define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD 71 | #else 72 | #define MICROPY_HW_BOARD_NAME "zephyr-generic" 73 | #endif 74 | 75 | #ifdef CONFIG_SOC 76 | #define MICROPY_HW_MCU_NAME CONFIG_SOC 77 | #else 78 | #define MICROPY_HW_MCU_NAME "unknown-cpu" 79 | #endif 80 | 81 | typedef int mp_int_t; // must be pointer size 82 | typedef unsigned mp_uint_t; // must be pointer size 83 | typedef long mp_off_t; 84 | 85 | #define MP_STATE_PORT MP_STATE_VM 86 | 87 | #define MICROPY_PORT_ROOT_POINTERS \ 88 | const char *readline_hist[8]; 89 | -------------------------------------------------------------------------------- /tools/imgtool/keys/rsa_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for RSA keys 3 | """ 4 | 5 | import io 6 | import os 7 | import sys 8 | import tempfile 9 | import unittest 10 | 11 | from cryptography.exceptions import InvalidSignature 12 | from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1 13 | from cryptography.hazmat.primitives.hashes import SHA256 14 | 15 | # Setup sys path so 'imgtool' is in it. 16 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) 17 | 18 | from imgtool.keys import load, RSA2048, RSAUsageError 19 | 20 | class KeyGeneration(unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.test_dir = tempfile.TemporaryDirectory() 24 | 25 | def tname(self, base): 26 | return os.path.join(self.test_dir.name, base) 27 | 28 | def tearDown(self): 29 | self.test_dir.cleanup() 30 | 31 | def test_keygen(self): 32 | name1 = self.tname("keygen.pem") 33 | k = RSA2048.generate() 34 | k.export_private(name1, b'secret') 35 | 36 | # Try loading the key without a password. 37 | self.assertIsNone(load(name1)) 38 | 39 | k2 = load(name1, b'secret') 40 | 41 | pubname = self.tname('keygen-pub.pem') 42 | k2.export_public(pubname) 43 | pk2 = load(pubname) 44 | 45 | # We should be able to export the public key from the loaded 46 | # public key, but not the private key. 47 | pk2.export_public(self.tname('keygen-pub2.pem')) 48 | self.assertRaises(RSAUsageError, pk2.export_private, self.tname('keygen-priv2.pem')) 49 | 50 | def test_emit(self): 51 | """Basic sanity check on the code emitters.""" 52 | k = RSA2048.generate() 53 | 54 | ccode = io.StringIO() 55 | k.emit_c(ccode) 56 | self.assertIn("rsa_pub_key", ccode.getvalue()) 57 | self.assertIn("rsa_pub_key_len", ccode.getvalue()) 58 | 59 | rustcode = io.StringIO() 60 | k.emit_rust(rustcode) 61 | self.assertIn("RSA_PUB_KEY", rustcode.getvalue()) 62 | 63 | def test_emit_pub(self): 64 | """Basic sanity check on the code emitters, from public key.""" 65 | pubname = self.tname("public.pem") 66 | k = RSA2048.generate() 67 | k.export_public(pubname) 68 | 69 | k2 = load(pubname) 70 | 71 | ccode = io.StringIO() 72 | k2.emit_c(ccode) 73 | self.assertIn("rsa_pub_key", ccode.getvalue()) 74 | self.assertIn("rsa_pub_key_len", ccode.getvalue()) 75 | 76 | rustcode = io.StringIO() 77 | k2.emit_rust(rustcode) 78 | self.assertIn("RSA_PUB_KEY", rustcode.getvalue()) 79 | 80 | def test_sig(self): 81 | k = RSA2048.generate() 82 | buf = b'This is the message' 83 | sig = k.sign(buf) 84 | 85 | # The code doesn't have any verification, so verify this 86 | # manually. 87 | k.key.public_key().verify( 88 | signature=sig, 89 | data=buf, 90 | padding=PSS(mgf=MGF1(SHA256()), salt_length=32), 91 | algorithm=SHA256()) 92 | 93 | # Modify the message to make sure the signature fails. 94 | self.assertRaises(InvalidSignature, 95 | k.key.public_key().verify, 96 | signature=sig, 97 | data=b'This is thE message', 98 | padding=PSS(mgf=MGF1(SHA256()), salt_length=32), 99 | algorithm=SHA256()) 100 | 101 | if __name__ == '__main__': 102 | unittest.main() 103 | -------------------------------------------------------------------------------- /tools/imgtool/keys/ecdsa.py: -------------------------------------------------------------------------------- 1 | """ 2 | ECDSA key management 3 | """ 4 | 5 | from cryptography.hazmat.backends import default_backend 6 | from cryptography.hazmat.primitives import serialization 7 | from cryptography.hazmat.primitives.asymmetric import ec 8 | from cryptography.hazmat.primitives.hashes import SHA256 9 | 10 | from .general import KeyClass 11 | 12 | class ECDSAUsageError(Exception): 13 | pass 14 | 15 | class ECDSA256P1Public(KeyClass): 16 | def __init__(self, key): 17 | self.key = key 18 | 19 | def shortname(self): 20 | return "ecdsa" 21 | 22 | def _unsupported(self, name): 23 | raise ECDSAUsageError("Operation {} requires private key".format(name)) 24 | 25 | def _get_public(self): 26 | return self.key 27 | 28 | def get_public_bytes(self): 29 | # The key is embedded into MBUboot in "SubjectPublicKeyInfo" format 30 | return self._get_public().public_bytes( 31 | encoding=serialization.Encoding.DER, 32 | format=serialization.PublicFormat.SubjectPublicKeyInfo) 33 | 34 | def export_private(self, path, passwd=None): 35 | self._unsupported('export_private') 36 | 37 | def export_public(self, path): 38 | """Write the public key to the given file.""" 39 | pem = self._get_public().public_bytes( 40 | encoding=serialization.Encoding.PEM, 41 | format=serialization.PublicFormat.SubjectPublicKeyInfo) 42 | with open(path, 'wb') as f: 43 | f.write(pem) 44 | 45 | def sig_type(self): 46 | return "ECDSA256_SHA256" 47 | 48 | def sig_tlv(self): 49 | return "ECDSA256" 50 | 51 | def sig_len(self): 52 | # The DER encoding depends on the high bit, and can be 53 | # anywhere from 70 to 72 bytes. Because we have to fill in 54 | # the length field before computing the signature, however, 55 | # we'll give the largest, and the sig checking code will allow 56 | # for it to be up to two bytes larger than the actual 57 | # signature. 58 | return 72 59 | 60 | class ECDSA256P1(ECDSA256P1Public): 61 | """ 62 | Wrapper around an ECDSA private key. 63 | """ 64 | 65 | def __init__(self, key): 66 | """key should be an instance of EllipticCurvePrivateKey""" 67 | self.key = key 68 | 69 | @staticmethod 70 | def generate(): 71 | pk = ec.generate_private_key( 72 | ec.SECP256R1(), 73 | backend=default_backend()) 74 | return ECDSA256P1(pk) 75 | 76 | def _get_public(self): 77 | return self.key.public_key() 78 | 79 | def export_private(self, path, passwd=None): 80 | """Write the private key to the given file, protecting it with the optional password.""" 81 | if passwd is None: 82 | enc = serialization.NoEncryption() 83 | else: 84 | enc = serialization.BestAvailableEncryption(passwd) 85 | pem = self.key.private_bytes( 86 | encoding=serialization.Encoding.PEM, 87 | format=serialization.PrivateFormat.PKCS8, 88 | encryption_algorithm=enc) 89 | with open(path, 'wb') as f: 90 | f.write(pem) 91 | 92 | def raw_sign(self, payload): 93 | """Return the actual signature""" 94 | return self.key.sign( 95 | data=payload, 96 | signature_algorithm=ec.ECDSA(SHA256())) 97 | 98 | def sign(self, payload): 99 | # To make fixed length, pad with one or two zeros. 100 | sig = self.raw_sign(payload) 101 | sig += b'\000' * (self.sig_len() - len(sig)) 102 | return sig 103 | -------------------------------------------------------------------------------- /degu_pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | void degu_ext_device_power(bool enable) 31 | { 32 | struct device *gpio0 = device_get_binding(DT_GPIO_P0_DEV_NAME); 33 | struct device *gpio1 = device_get_binding(DT_GPIO_P1_DEV_NAME); 34 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 35 | struct device *i2c0 = device_get_binding(DT_I2C_0_NAME); 36 | struct device *i2c1 = device_get_binding(DT_I2C_1_NAME); 37 | #endif 38 | 39 | if (enable) { 40 | gpio_pin_configure(gpio1, 6, GPIO_PUD_PULL_UP); 41 | gpio_pin_write(gpio1, 6, 1); 42 | gpio_pin_configure(gpio1, 2, GPIO_PUD_PULL_UP); 43 | gpio_pin_write(gpio1, 2, 1); 44 | gpio_pin_configure(gpio0, 26, GPIO_PUD_PULL_UP); 45 | gpio_pin_write(gpio0, 26, 1); 46 | 47 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 48 | device_set_power_state(i2c1, DEVICE_PM_ACTIVE_STATE, NULL, NULL); 49 | device_set_power_state(i2c0, DEVICE_PM_ACTIVE_STATE, NULL, NULL); 50 | } else { 51 | device_set_power_state(i2c0, DEVICE_PM_SUSPEND_STATE, NULL, NULL); 52 | device_set_power_state(i2c1, DEVICE_PM_SUSPEND_STATE, NULL, NULL); 53 | #else 54 | } else { 55 | #endif 56 | gpio_pin_configure(gpio0, 26, GPIO_PUD_PULL_DOWN); 57 | gpio_pin_write(gpio0, 26, 0); 58 | gpio_pin_configure(gpio1, 2, GPIO_PUD_PULL_DOWN); 59 | gpio_pin_write(gpio1, 2, 0); 60 | gpio_pin_configure(gpio1, 6, GPIO_PUD_PULL_DOWN); 61 | gpio_pin_write(gpio1, 6, 0); 62 | 63 | gpio_pin_configure(gpio0, 24, GPIO_PUD_PULL_DOWN); 64 | gpio_pin_write(gpio0, 24, 0); 65 | gpio_pin_configure(gpio0, 25, GPIO_PUD_PULL_DOWN); 66 | gpio_pin_write(gpio0, 25, 0); 67 | 68 | gpio_pin_configure(gpio0, 7, GPIO_PUD_PULL_DOWN); 69 | gpio_pin_write(gpio0, 7, 0); 70 | gpio_pin_configure(gpio1, 8, GPIO_PUD_PULL_DOWN); 71 | gpio_pin_write(gpio1, 8, 0); 72 | } 73 | } 74 | 75 | void openthread_suspend(otInstance *aInstance) 76 | { 77 | otThreadSetEnabled(aInstance, false); 78 | otIp6SetEnabled(aInstance, false); 79 | otPlatRadioSleep(aInstance); 80 | otPlatRadioDisable(aInstance); 81 | } 82 | 83 | void openthread_resume(otInstance *aInstance, uint8_t aChannel, otLinkModeConfig aConfig) 84 | { 85 | s64_t uptime = k_uptime_get(); 86 | u32_t timeout = K_SECONDS(3); 87 | 88 | u32_t elapsed = 0; 89 | 90 | otPlatRadioEnable(aInstance); 91 | otPlatRadioReceive(aInstance, aChannel); 92 | otThreadSetLinkMode(aInstance, aConfig); 93 | otIp6SetEnabled(aInstance, true); 94 | otThreadSetEnabled(aInstance, true); 95 | k_usleep(200); 96 | while(otThreadGetDeviceRole(aInstance) <= OT_DEVICE_ROLE_DETACHED) 97 | { 98 | elapsed += k_uptime_delta_32(&uptime); 99 | if(elapsed >= timeout){ 100 | break; 101 | } 102 | k_usleep(USEC_PER_MSEC * 10U); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /moddegu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "py/nlr.h" 4 | #include "py/obj.h" 5 | #include "py/runtime.h" 6 | #include "py/binary.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "zcoap.h" 18 | #include "degu_utils.h" 19 | #include "degu_ota.h" 20 | #include "degu_pm.h" 21 | 22 | STATIC mp_obj_t degu_check_update(void) { 23 | return mp_obj_new_int(check_update()); 24 | } 25 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(degu_check_update_obj, degu_check_update); 26 | 27 | STATIC mp_obj_t degu_update_shadow(mp_obj_t shadow) { 28 | int ret = degu_coap_request("thing", COAP_METHOD_POST, (u8_t *)mp_obj_str_get_str(shadow), NULL); 29 | 30 | return mp_obj_new_int(ret); 31 | } 32 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(degu_update_shadow_obj, degu_update_shadow); 33 | 34 | STATIC mp_obj_t degu_get_shadow(void) { 35 | vstr_t vstr; 36 | int ret; 37 | u8_t *payload = (u8_t *)m_malloc(MAX_COAP_MSG_LEN); 38 | 39 | if (!payload) { 40 | printf("can't malloc\n"); 41 | return mp_const_none; 42 | } 43 | memset(payload, 0, MAX_COAP_MSG_LEN); 44 | 45 | ret = degu_coap_request("thing", COAP_METHOD_GET, payload, NULL); 46 | 47 | if (payload != NULL && ret >= COAP_RESPONSE_CODE_OK) { 48 | vstr_init_len(&vstr, strlen(payload)); 49 | strcpy(vstr.buf, payload); 50 | m_free(payload); 51 | return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); 52 | } 53 | else { 54 | m_free(payload); 55 | return mp_const_none; 56 | } 57 | } 58 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(degu_get_shadow_obj, degu_get_shadow); 59 | 60 | STATIC mp_obj_t mod_suspend(mp_obj_t time_sec) 61 | { 62 | s32_t time_to_wake = mp_obj_get_int(time_sec); 63 | 64 | struct net_if *iface; 65 | struct openthread_context *ot_context; 66 | otLinkModeConfig config; 67 | uint8_t channel; 68 | 69 | iface = net_if_get_default(); 70 | ot_context = net_if_l2_data(iface); 71 | channel = otLinkGetChannel(ot_context->instance); 72 | config = otThreadGetLinkMode(ot_context->instance); 73 | 74 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 75 | sys_pm_ctrl_enable_state(SYS_POWER_STATE_SLEEP_3); 76 | sys_set_power_state(SYS_POWER_STATE_SLEEP_3); 77 | #endif 78 | 79 | openthread_suspend(ot_context->instance); 80 | k_sleep(K_SECONDS(time_to_wake)); 81 | openthread_resume(ot_context->instance, channel, config); 82 | 83 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 84 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_SLEEP_3); 85 | #endif 86 | 87 | return mp_const_none; 88 | } 89 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_suspend_obj, mod_suspend); 90 | 91 | STATIC mp_obj_t mod_powerdown(void) 92 | { 93 | degu_ext_device_power(false); 94 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 95 | sys_pm_suspend_devices(); 96 | #endif 97 | 98 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 99 | sys_pm_ctrl_enable_state(SYS_POWER_STATE_DEEP_SLEEP_1); 100 | sys_set_power_state(SYS_POWER_STATE_DEEP_SLEEP_1); 101 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_DEEP_SLEEP_1); 102 | #endif 103 | 104 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT 105 | sys_pm_resume_devices(); 106 | #endif 107 | return mp_const_none; 108 | } 109 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_powerdown_obj, mod_powerdown); 110 | 111 | STATIC const mp_rom_map_elem_t degu_globals_table[] = { 112 | {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_degu) }, 113 | { MP_ROM_QSTR(MP_QSTR_check_update), MP_ROM_PTR(°u_check_update_obj) }, 114 | { MP_ROM_QSTR(MP_QSTR_update_shadow), MP_ROM_PTR(°u_update_shadow_obj) }, 115 | { MP_ROM_QSTR(MP_QSTR_get_shadow), MP_ROM_PTR(°u_get_shadow_obj) }, 116 | { MP_ROM_QSTR(MP_QSTR_suspend), MP_ROM_PTR(&mod_suspend_obj) }, 117 | { MP_ROM_QSTR(MP_QSTR_powerdown), MP_ROM_PTR(&mod_powerdown_obj) }, 118 | }; 119 | 120 | STATIC MP_DEFINE_CONST_DICT (mp_module_degu_globals, degu_globals_table); 121 | 122 | const mp_obj_module_t mp_module_degu = { 123 | .base = { &mp_type_module }, 124 | .globals = (mp_obj_dict_t*)&mp_module_degu_globals, 125 | }; 126 | -------------------------------------------------------------------------------- /prj_degu_evk.conf: -------------------------------------------------------------------------------- 1 | # Degu default = MTD 2 | CONFIG_OPENTHREAD_MTD=y 3 | 4 | # Degu uses MCUboot to update firmware 5 | CONFIG_BOOTLOADER_MCUBOOT=y 6 | 7 | CONFIG_SHELL=y 8 | CONFIG_CPLUSPLUS=y 9 | CONFIG_OVERRIDE_FRAME_POINTER_DEFAULT=y 10 | CONFIG_OMIT_FRAME_POINTER=y 11 | 12 | # Disable TCP and IPv4 13 | CONFIG_NETWORKING=y 14 | CONFIG_NET_UDP=y 15 | CONFIG_NET_TCP=n 16 | CONFIG_NET_IPV6=y 17 | CONFIG_NET_IPV4=n 18 | CONFIG_NET_SOCKETS=y 19 | CONFIG_NET_SOCKETS_POSIX_NAMES=y 20 | CONFIG_NET_SOCKETS_POLL_MAX=4 21 | CONFIG_NET_SOCKETS_SOCKOPT_TLS=y 22 | CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6 23 | CONFIG_NET_SOCKETS_ENABLE_DTLS=y 24 | CONFIG_NET_SOCKETS_DTLS_TIMEOUT=30000 25 | CONFIG_POSIX_MAX_FDS=6 26 | CONFIG_NET_CONNECTION_MANAGER=y 27 | 28 | CONFIG_NET_IPV6_NBR_CACHE=n 29 | CONFIG_NET_IPV6_MLD=n 30 | CONFIG_NET_CONFIG_NEED_IPV6=y 31 | CONFIG_NET_CONFIG_NEED_IPV4=n 32 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="" 33 | CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" 34 | 35 | CONFIG_MAIN_STACK_SIZE=4096 36 | CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 37 | CONFIG_NET_TX_STACK_SIZE=2048 38 | CONFIG_NET_RX_STACK_SIZE=5120 39 | CONFIG_SHELL_STACK_SIZE=3072 40 | CONFIG_NET_PKT_RX_COUNT=16 41 | CONFIG_NET_PKT_TX_COUNT=16 42 | CONFIG_NET_BUF_RX_COUNT=100 43 | CONFIG_NET_BUF_TX_COUNT=100 44 | CONFIG_NET_CONTEXT_NET_PKT_POOL=y 45 | CONFIG_ENTROPY_GENERATOR=y 46 | CONFIG_TEST_RANDOM_GENERATOR=y 47 | CONFIG_INIT_STACKS=y 48 | #CONFIG_NET_SHELL=y 49 | 50 | # Thread by default registers quite a lot addresses. 51 | CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6 52 | CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=8 53 | CONFIG_NET_MAX_CONTEXTS=10 54 | 55 | # Disable conflicting IEEE802154 L2 56 | CONFIG_NET_L2_IEEE802154=n 57 | CONFIG_NET_L2_IEEE802154_SHELL=n 58 | 59 | CONFIG_NET_L2_OPENTHREAD=y 60 | 61 | CONFIG_OPENTHREAD_DEBUG=y 62 | CONFIG_OPENTHREAD_L2_DEBUG=y 63 | CONFIG_OPENTHREAD_L2_LOG_LEVEL_INF=y 64 | 65 | CONFIG_OPENTHREAD_CHANNEL=26 66 | 67 | # Other OpenThread dependencies (flash for OT persistent storage) 68 | CONFIG_FLASH=y 69 | CONFIG_FLASH_PAGE_LAYOUT=y 70 | CONFIG_MPU_ALLOW_FLASH_WRITE=y 71 | 72 | #fixup for CONFIG_IEEE802154_DRIVER_LOG_LEVEL undeclared 73 | CONFIG_NET_LOG=y 74 | CONFIG_LOG=y 75 | CONFIG_NET_STATISTICS=y 76 | CONFIG_PRINTK=y 77 | 78 | CONFIG_OPENTHREAD_JOINER=y 79 | CONFIG_OPENTHREAD_COMMISSIONER=y 80 | CONFIG_OPENTHREAD_NETWORK_NAME="degu" 81 | CONFIG_OPENTHREAD_JOINER_AUTOSTART=y 82 | CONFIG_OPENTHREAD_JOINER_AUTOSTART_RETRY=y 83 | CONFIG_OPENTHREAD_JOINER_PSKD="DEGUPSK" 84 | 85 | # for modzcoap 86 | CONFIG_COAP=y 87 | 88 | # for flash 89 | CONFIG_USB_MASS_STORAGE=y 90 | CONFIG_DISK_ACCESS_FLASH=y 91 | CONFIG_MASS_STORAGE_DISK_NAME="NAND" 92 | CONFIG_USB_COMPOSITE_DEVICE=y 93 | 94 | CONFIG_FILE_SYSTEM=y 95 | CONFIG_HEAP_MEM_POOL_SIZE=40090 96 | CONFIG_FAT_FILESYSTEM_ELM=y 97 | CONFIG_FILE_SYSTEM_SHELL=y 98 | 99 | #for update 100 | CONFIG_JSON_LIBRARY=y 101 | 102 | #TLS 103 | CONFIG_MBEDTLS=y 104 | CONFIG_MBEDTLS_BUILTIN=y 105 | CONFIG_MBEDTLS_ENABLE_HEAP=y 106 | CONFIG_MBEDTLS_HEAP_SIZE=56240 107 | CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048 108 | CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=y 109 | CONFIG_MBEDTLS_SSL_VERIFY_OPTIONAL_ENABLED=y 110 | CONFIG_MBEDTLS_MAC_MD5_ENABLED=y 111 | 112 | #for PM 113 | CONFIG_LOG_PROCESS_THREAD=n 114 | CONFIG_SYS_CLOCK_TICKS_PER_SEC=128 115 | 116 | CONFIG_SYS_POWER_MANAGEMENT=y 117 | CONFIG_SYS_POWER_SLEEP_STATES=y 118 | CONFIG_SYS_POWER_DEEP_SLEEP_STATES=y 119 | # CONFIG_HAS_SYS_POWER_STATE_SLEEP_1=y 120 | # CONFIG_HAS_SYS_POWER_STATE_SLEEP_2=y 121 | # CONFIG_HAS_SYS_POWER_STATE_SLEEP_3=y 122 | # CONFIG_HAS_SYS_POWER_STATE_DEEP_SLEEP_1=y 123 | # CONFIG_HAS_SYS_POWER_STATE_DEEP_SLEEP_2=y 124 | # CONFIG_HAS_SYS_POWER_STATE_DEEP_SLEEP_3=y 125 | CONFIG_SYS_PM_STATE_LOCK=y 126 | CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_1=5 127 | CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_2=10 128 | CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_3=20 129 | CONFIG_DEVICE_POWER_MANAGEMENT=y 130 | 131 | #Secure Element 132 | CONFIG_SE_HOSTLIB=y 133 | CONFIG_I2C_GPIO=y 134 | CONFIG_I2C_GPIO_SDA_NO_OPENDRAIN=y 135 | CONFIG_I2C_GPIO_SCL_NO_OPENDRAIN=y 136 | CONFIG_I2C_GPIO_0=y 137 | CONFIG_I2C_GPIO_0_NAME="I2C_0" 138 | CONFIG_I2C_GPIO_0_GPIO="GPIO_0" 139 | CONFIG_I2C_GPIO_0_SCL_PIN=22 140 | CONFIG_I2C_GPIO_0_SDA_PIN=20 141 | CONFIG_I2C_BITBANG=y 142 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is the main Makefile, which uses MicroPython build system, 3 | # but Zephyr arch-specific toolchain and target-specific flags. 4 | # This Makefile builds MicroPython as a library, and then calls 5 | # recursively Makefile.zephyr to build complete application binary 6 | # using Zephyr build system. 7 | # 8 | BOARD ?= degu_evk 9 | CMAKE_BUILD_TYPE ?= MinSizeRel 10 | CONF_FILE = prj_$(BOARD)_merged.conf 11 | OUTDIR_PREFIX = $(BOARD) 12 | 13 | # Default heap size is 16KB, which is on conservative side, to let 14 | # it build for smaller boards, but it won't be enough for larger 15 | # applications, and will need to be increased. 16 | MICROPY_HEAP_SIZE = 32768 17 | FROZEN_DIR = scripts 18 | 19 | # Default target 20 | all: 21 | 22 | include micropython/py/mkenv.mk 23 | include $(TOP)/py/py.mk 24 | 25 | # Zephyr (generated) config files - must be defined before include below 26 | Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export 27 | ifneq ($(MAKECMDGOALS), clean) 28 | include $(Z_EXPORTS) 29 | endif 30 | 31 | INC += -I. 32 | INC += -I$(TOP) 33 | INC += -I$(BUILD) 34 | INC += -I$(ZEPHYR_BASE)/net/ip 35 | INC += -I$(ZEPHYR_BASE)/net/ip/contiki 36 | INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os 37 | INC += -I$(PWD)/modules/crypto/mbedtls/include 38 | INC += -I$(PWD)/modules/fs/fatfs/include 39 | 40 | SRC_C = main.c \ 41 | degu_utils.c \ 42 | degu_ota.c \ 43 | degu_pm.c \ 44 | zcoap.c \ 45 | help.c \ 46 | modusocket.c \ 47 | modutime.c \ 48 | modzephyr.c \ 49 | modzsensor.c \ 50 | modmachine.c \ 51 | moddegu.c \ 52 | machine_i2c.c \ 53 | machine_adc.c \ 54 | machine_pin.c \ 55 | machine_uart.c \ 56 | uart_core.c \ 57 | lib/utils/stdout_helpers.c \ 58 | lib/utils/printf.c \ 59 | lib/utils/pyexec.c \ 60 | lib/utils/interrupt_char.c \ 61 | lib/mp-readline/readline.c \ 62 | $(SRC_MOD) 63 | 64 | # List of sources for qstr extraction 65 | SRC_QSTR += $(SRC_C) 66 | 67 | OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) 68 | 69 | CFLAGS = $(Z_CFLAGS) \ 70 | -std=gnu99 -D_ISOC99_SOURCE -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) 71 | 72 | include $(TOP)/py/mkrules.mk 73 | 74 | GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver 75 | KCONFIG_TARGETS = \ 76 | initconfig config nconfig menuconfig xconfig gconfig \ 77 | oldconfig silentoldconfig defconfig savedefconfig \ 78 | allnoconfig allyesconfig alldefconfig randconfig \ 79 | listnewconfig olddefconfig 80 | CLEAN_TARGETS = pristine mrproper 81 | 82 | $(GENERIC_TARGETS): $(LIBMICROPYTHON) 83 | $(CLEAN_TARGETS): clean 84 | 85 | $(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): 86 | $(MAKE) -j -C outdir/$(BOARD) $@ 87 | 88 | $(LIBMICROPYTHON): | $(Z_EXPORTS) 89 | build/genhdr/qstr.i.last: | $(Z_EXPORTS) 90 | 91 | # If we recreate libmicropython, also cause zephyr.bin relink 92 | LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk 93 | 94 | # MicroPython's global clean cleans everything, fast 95 | CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf degu.bin 96 | 97 | # Clean Zephyr things in Zephyr way 98 | z_clean: 99 | $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean 100 | 101 | # This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which 102 | # can be overriden. 103 | # prj_$(BOARD).conf is optional, that's why it's resolved with $(wildcard) 104 | # function. 105 | prj_$(BOARD)_merged.conf: prj_base.conf $(wildcard prj_$(BOARD).conf) 106 | $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ 107 | 108 | cmake: outdir/$(BOARD)/Makefile 109 | 110 | 111 | outdir/$(BOARD)/Makefile: $(CONF_FILE) 112 | $(info ${BUILD_TYPE}) 113 | mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DEXTERNAL_PROJECT_PATH_OPENTHREAD=$(EXTERNAL_PROJECT_PATH_OPENTHREAD) -DCONF_FILE=$(CONF_FILE) -Boutdir/$(BOARD) -H. 114 | 115 | $(Z_EXPORTS): outdir/$(BOARD)/Makefile 116 | make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ 117 | make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target kobj_types_h_target 118 | 119 | degu.bin: outdir/$(BOARD)/zephyr/zephyr.bin 120 | ./tools/imgtool.py sign --key root-rsa-2048.pem --header-size 0x200 --align 8 --version 1.0 --slot-size 0x6e000 $< $@ 121 | -------------------------------------------------------------------------------- /machine_adc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Hiroaki OHSAWA 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "adc.h" 28 | #include "py/runtime.h" 29 | #include "py/mphal.h" 30 | #include "modmachine.h" 31 | 32 | static struct adc_sequence_options options = { 33 | .interval_us = 12, 34 | .extra_samplings = 0, 35 | }; 36 | 37 | static struct adc_sequence adc_seq = { 38 | .options = &options, 39 | }; 40 | 41 | const mp_obj_base_t machine_adc_obj_template = {&machine_adc_type}; 42 | 43 | #define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } 44 | 45 | #define ADC_DEV "ADC_0" 46 | 47 | mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, 48 | const mp_obj_t *args) { 49 | mp_arg_check_num(n_args, n_kw, 1, 1, true); 50 | machine_adc_obj_t *self = m_new_obj(machine_adc_obj_t); 51 | uint8_t adc_id = mp_obj_get_int(args[0]); 52 | 53 | self->dev = device_get_binding(ADC_DEV); 54 | if (self->dev == NULL) { 55 | mp_raise_ValueError("device not found"); 56 | } 57 | self->base = machine_adc_obj_template; 58 | self->adc_channel = adc_id; 59 | self->cfg = m_new_obj(struct adc_channel_cfg); 60 | self->cfg->channel_id = self->adc_channel; 61 | self->cfg->differential = false; 62 | self->cfg->gain = ADC_GAIN_1_6; 63 | self->cfg->reference = ADC_REF_INTERNAL; 64 | self->cfg->acquisition_time = ADC_ACQ_TIME_DEFAULT; 65 | self->cfg->input_positive = self->adc_channel + 1; 66 | RAISE_ERRNO(adc_channel_setup(self->dev, self->cfg)); 67 | return (mp_obj_t)self; 68 | } 69 | 70 | STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 71 | machine_adc_obj_t *self = self_in; 72 | mp_printf(print, "ADC/A%u", self->adc_channel); 73 | } 74 | 75 | #include 76 | STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) { 77 | machine_adc_obj_t *self = self_in; 78 | adc_seq.buffer = &(self->buffer); 79 | adc_seq.channels = BIT(self->adc_channel); 80 | adc_seq.resolution = 12; 81 | adc_seq.buffer_size = sizeof(self->buffer); //self->buffer 82 | RAISE_ERRNO(adc_read(self->dev, &adc_seq)); 83 | return MP_OBJ_NEW_SMALL_INT((u16_t)self->buffer); 84 | } 85 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read); 86 | 87 | STATIC mp_obj_t machine_adc_gain(mp_obj_t self_in, mp_obj_t gain_in) { 88 | machine_adc_obj_t *self = self_in; 89 | self->cfg->gain = MP_OBJ_QSTR_VALUE(gain_in); 90 | return mp_const_none; 91 | } 92 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_adc_gain_obj, machine_adc_gain); 93 | 94 | 95 | STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { 96 | { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_adc_read_obj) }, 97 | { MP_ROM_QSTR(MP_QSTR_gain), MP_ROM_PTR(&machine_adc_gain_obj) }, 98 | 99 | { MP_ROM_QSTR(MP_QSTR_GAIN_1_6), MP_ROM_INT(ADC_GAIN_1_6) }, 100 | { MP_ROM_QSTR(MP_QSTR_GAIN_1_5), MP_ROM_INT(ADC_GAIN_1_5) }, 101 | { MP_ROM_QSTR(MP_QSTR_GAIN_1_4), MP_ROM_INT(ADC_GAIN_1_4) }, 102 | { MP_ROM_QSTR(MP_QSTR_GAIN_1_3), MP_ROM_INT(ADC_GAIN_1_3) }, 103 | { MP_ROM_QSTR(MP_QSTR_GAIN_1_2), MP_ROM_INT(ADC_GAIN_1_2) }, 104 | { MP_ROM_QSTR(MP_QSTR_GAIN_2_3), MP_ROM_INT(ADC_GAIN_2_3) }, 105 | { MP_ROM_QSTR(MP_QSTR_GAIN_1), MP_ROM_INT(ADC_GAIN_1) }, 106 | { MP_ROM_QSTR(MP_QSTR_GAIN_2), MP_ROM_INT(ADC_GAIN_2) }, 107 | { MP_ROM_QSTR(MP_QSTR_GAIN_3), MP_ROM_INT(ADC_GAIN_3) }, 108 | { MP_ROM_QSTR(MP_QSTR_GAIN_4), MP_ROM_INT(ADC_GAIN_4) }, 109 | { MP_ROM_QSTR(MP_QSTR_GAIN_8), MP_ROM_INT(ADC_GAIN_8) }, 110 | { MP_ROM_QSTR(MP_QSTR_GAIN_16), MP_ROM_INT(ADC_GAIN_16) }, 111 | { MP_ROM_QSTR(MP_QSTR_GAIN_32), MP_ROM_INT(ADC_GAIN_32) }, 112 | { MP_ROM_QSTR(MP_QSTR_GAIN_64), MP_ROM_INT(ADC_GAIN_64) }, 113 | }; 114 | 115 | STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); 116 | 117 | const mp_obj_type_t machine_adc_type = { 118 | { &mp_type_type }, 119 | .name = MP_QSTR_ADC, 120 | .print = machine_adc_print, 121 | .make_new = machine_adc_make_new, 122 | .locals_dict = (mp_obj_t)&machine_adc_locals_dict, 123 | }; 124 | -------------------------------------------------------------------------------- /src/zephyr_start.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Atmark Techno, Inc. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include 27 | #include 28 | #include 29 | #include "zephyr_getchar.h" 30 | #include "../degu_ota.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include "../version.h" 41 | 42 | #ifdef ROUTER_ONLY 43 | #include 44 | #include 45 | #include 46 | #include 47 | #define OT_LEADER_WEIGHT 1 48 | #endif 49 | 50 | 51 | LOG_MODULE_REGISTER(main); 52 | 53 | #ifndef ROUTER_ONLY 54 | int real_main(void); 55 | int bg_main(char *src, size_t len); 56 | #endif 57 | static const char splash[] = "Start background micropython process.\r\n"; 58 | bool mp_running = 0; 59 | 60 | FATFS fsdata; 61 | static struct fs_mount_t fatfs_mnt = { 62 | .type = FS_FATFS, 63 | .fs_data = &fsdata, 64 | }; 65 | 66 | 67 | static int mount_fat(void) 68 | { 69 | int res; 70 | fatfs_mnt.mnt_point = "/NAND:"; 71 | 72 | res = fs_mount(&fatfs_mnt); 73 | if (res != 0) { 74 | LOG_INF("Error mounting fat fs.Error Code [%d]", res); 75 | return -1; 76 | } 77 | return 0; 78 | } 79 | 80 | 81 | int run_user_script(char *path) { 82 | struct fs_file_t file; 83 | struct fs_dirent dirent; 84 | int err, offset = 0; 85 | static char *file_data; 86 | static size_t len; 87 | char version[32]; 88 | 89 | err = fs_stat(path, &dirent); 90 | if(err) { 91 | LOG_ERR("Failed to stat file"); 92 | goto no_script; 93 | } 94 | 95 | err = fs_open(&file, path); 96 | if(err) { 97 | LOG_ERR("Can't open file"); 98 | goto no_script; 99 | } 100 | 101 | if (offset > 0) { 102 | fs_seek(&file, offset, FS_SEEK_SET); 103 | } 104 | len = dirent.size; 105 | file_data = k_malloc(len); 106 | int count = INT_MAX; 107 | int read = 0; 108 | while(1){ 109 | read = fs_read(&file, file_data + offset, MIN(count, len)); 110 | if (read <= 0) { 111 | break; 112 | } 113 | offset += read; 114 | count -= read; 115 | } 116 | 117 | sprintf(version, "Degu F/W version: %s.%s.%s\r\n", VERSION_MAJOR, 118 | VERSION_MINOR, VERSION_REVISION); 119 | console_init(); 120 | console_write(NULL, version, strlen(version)); 121 | console_write(NULL, splash, sizeof(splash) - 1); 122 | 123 | #ifndef ROUTER_ONLY 124 | bg_main(file_data, len); 125 | #endif 126 | fs_close(&file); 127 | k_free(file_data); 128 | return 1; 129 | no_script: 130 | return 0; 131 | } 132 | 133 | void main(void) { 134 | int err = 0; 135 | 136 | #ifdef ROUTER_ONLY 137 | struct net_if *iface = net_if_get_default(); 138 | struct openthread_context *ot_context = net_if_l2_data(iface); 139 | otThreadSetLocalLeaderWeight(ot_context->instance, OT_LEADER_WEIGHT); 140 | #endif 141 | 142 | #ifdef CONFIG_SYS_POWER_MANAGEMENT 143 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_SLEEP_1); 144 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_SLEEP_2); 145 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_SLEEP_3); 146 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_DEEP_SLEEP_1); 147 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_DEEP_SLEEP_2); 148 | sys_pm_ctrl_disable_state(SYS_POWER_STATE_DEEP_SLEEP_3); 149 | #endif 150 | 151 | err = mount_fat(); 152 | if (err) { 153 | LOG_ERR("Failed to mount user region"); 154 | } 155 | 156 | #ifndef ROUTER_ONLY 157 | if(update_init() == DEGU_OTA_OK){ 158 | if (check_update() == DEGU_OTA_OK) { 159 | LOG_INF("Trying to update..."); 160 | if (do_update() == DEGU_OTA_OK) { 161 | sys_reboot(SYS_REBOOT_COLD); 162 | } 163 | } 164 | } 165 | 166 | mp_running = run_user_script("/NAND:/main.py"); 167 | #endif 168 | } 169 | 170 | static int cmd_upython(const struct shell *shell, size_t argc, char **argv) 171 | { 172 | ARG_UNUSED(argc); 173 | ARG_UNUSED(argv); 174 | if (mp_running){ 175 | shell_print(shell, "WARNING: micropython already started background."); 176 | return 0; 177 | } 178 | 179 | console_init(); 180 | #ifndef ROUTER_ONLY 181 | real_main(); 182 | #endif 183 | return 0; 184 | } 185 | SHELL_CMD_REGISTER(upython, NULL, "micropython interpreterx`", cmd_upython); 186 | -------------------------------------------------------------------------------- /modzsensor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2018 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | 29 | #include "py/runtime.h" 30 | 31 | #include 32 | #include 33 | 34 | #if MICROPY_PY_ZSENSOR 35 | 36 | typedef struct _mp_obj_sensor_t { 37 | mp_obj_base_t base; 38 | struct device *dev; 39 | } mp_obj_sensor_t; 40 | 41 | STATIC mp_obj_t sensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { 42 | mp_arg_check_num(n_args, n_kw, 1, 1, false); 43 | mp_obj_sensor_t *o = m_new_obj(mp_obj_sensor_t); 44 | o->base.type = type; 45 | o->dev = device_get_binding(mp_obj_str_get_str(args[0])); 46 | if (o->dev == NULL) { 47 | mp_raise_ValueError("dev not found"); 48 | } 49 | return MP_OBJ_FROM_PTR(o); 50 | } 51 | 52 | STATIC mp_obj_t sensor_measure(mp_obj_t self_in) { 53 | mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); 54 | int st = sensor_sample_fetch(self->dev); 55 | if (st != 0) { 56 | mp_raise_OSError(-st); 57 | } 58 | return mp_const_none; 59 | } 60 | MP_DEFINE_CONST_FUN_OBJ_1(sensor_measure_obj, sensor_measure); 61 | 62 | STATIC void sensor_get_internal(mp_obj_t self_in, mp_obj_t channel_in, struct sensor_value *res) { 63 | mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); 64 | 65 | int st = sensor_channel_get(self->dev, mp_obj_get_int(channel_in), res); 66 | if (st != 0) { 67 | mp_raise_OSError(-st); 68 | } 69 | } 70 | 71 | STATIC mp_obj_t sensor_get_float(mp_obj_t self_in, mp_obj_t channel_in) { 72 | struct sensor_value val; 73 | sensor_get_internal(self_in, channel_in, &val); 74 | return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000); 75 | } 76 | MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_float_obj, sensor_get_float); 77 | 78 | STATIC mp_obj_t sensor_get_micros(mp_obj_t self_in, mp_obj_t channel_in) { 79 | struct sensor_value val; 80 | sensor_get_internal(self_in, channel_in, &val); 81 | return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2); 82 | } 83 | MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_micros_obj, sensor_get_micros); 84 | 85 | STATIC mp_obj_t sensor_get_millis(mp_obj_t self_in, mp_obj_t channel_in) { 86 | struct sensor_value val; 87 | sensor_get_internal(self_in, channel_in, &val); 88 | return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000); 89 | } 90 | MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_millis_obj, sensor_get_millis); 91 | 92 | STATIC mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) { 93 | struct sensor_value val; 94 | sensor_get_internal(self_in, channel_in, &val); 95 | return MP_OBJ_NEW_SMALL_INT(val.val1); 96 | } 97 | MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int); 98 | 99 | STATIC const mp_rom_map_elem_t sensor_locals_dict_table[] = { 100 | { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) }, 101 | { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) }, 102 | { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) }, 103 | { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) }, 104 | { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) }, 105 | }; 106 | 107 | STATIC MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table); 108 | 109 | STATIC const mp_obj_type_t sensor_type = { 110 | { &mp_type_type }, 111 | .name = MP_QSTR_Sensor, 112 | .make_new = sensor_make_new, 113 | .locals_dict = (void*)&sensor_locals_dict, 114 | }; 115 | 116 | STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { 117 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zsensor) }, 118 | { MP_ROM_QSTR(MP_QSTR_Sensor), MP_ROM_PTR(&sensor_type) }, 119 | 120 | #define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(SENSOR_CHAN_ ## name) } 121 | C(ACCEL_X), 122 | C(ACCEL_Y), 123 | C(ACCEL_Z), 124 | C(GYRO_X), 125 | C(GYRO_Y), 126 | C(GYRO_Z), 127 | C(MAGN_X), 128 | C(MAGN_Y), 129 | C(MAGN_Z), 130 | C(AMBIENT_TEMP), 131 | C(DIE_TEMP), 132 | C(PRESS), 133 | C(PROX), 134 | C(HUMIDITY), 135 | C(LIGHT), 136 | C(ALTITUDE), 137 | #undef C 138 | }; 139 | 140 | STATIC MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table); 141 | 142 | const mp_obj_module_t mp_module_zsensor = { 143 | .base = { &mp_type_module }, 144 | .globals = (mp_obj_dict_t*)&mp_module_zsensor_globals, 145 | }; 146 | 147 | #endif //MICROPY_PY_UHASHLIB 148 | -------------------------------------------------------------------------------- /mpconfigport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2016 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include 27 | 28 | // Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles 29 | #include "autoconf.h" 30 | // Included here to get basic Zephyr environment (macros, etc.) 31 | #include 32 | 33 | // Usually passed from Makefile 34 | #ifndef MICROPY_HEAP_SIZE 35 | #define MICROPY_HEAP_SIZE (32 * 1024) 36 | #endif 37 | 38 | #define MICROPY_ENABLE_SOURCE_LINE (1) 39 | #define MICROPY_STACK_CHECK (1) 40 | #define MICROPY_ENABLE_GC (1) 41 | #define MICROPY_HELPER_REPL (1) 42 | #define MICROPY_REPL_AUTO_INDENT (1) 43 | #define MICROPY_KBD_EXCEPTION (1) 44 | #define MICROPY_CPYTHON_COMPAT (0) 45 | #define MICROPY_PY_ASYNC_AWAIT (0) 46 | #define MICROPY_PY_ATTRTUPLE (0) 47 | #define MICROPY_PY_BUILTINS_ENUMERATE (0) 48 | #define MICROPY_PY_BUILTINS_FILTER (0) 49 | #define MICROPY_PY_BUILTINS_MIN_MAX (0) 50 | #define MICROPY_PY_BUILTINS_PROPERTY (1) 51 | #define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) 52 | #define MICROPY_PY_BUILTINS_REVERSED (0) 53 | #define MICROPY_PY_BUILTINS_SET (0) 54 | #define MICROPY_PY_BUILTINS_STR_COUNT (0) 55 | #define MICROPY_PY_BUILTINS_HELP (1) 56 | #define MICROPY_PY_BUILTINS_HELP_TEXT zephyr_help_text 57 | #define MICROPY_PY_ARRAY (1) 58 | #define MICROPY_PY_COLLECTIONS (0) 59 | #define MICROPY_PY_CMATH (0) 60 | #define MICROPY_PY_IO (1) 61 | #define MICROPY_PY_UJSON (1) 62 | #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) 63 | #define MICROPY_PY_MACHINE (1) 64 | #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new 65 | #define MICROPY_MODULE_WEAK_LINKS (1) 66 | #define MICROPY_PY_STRUCT (1) 67 | #ifdef CONFIG_NETWORKING 68 | // If we have networking, we likely want errno comfort 69 | #define MICROPY_PY_UERRNO (1) 70 | #define MICROPY_PY_USOCKET (1) 71 | #endif 72 | #define MICROPY_PY_UBINASCII (1) 73 | #define MICROPY_PY_UHASHLIB (1) 74 | #define MICROPY_PY_UTIME (1) 75 | #define MICROPY_PY_UTIME_MP_HAL (1) 76 | #define MICROPY_PY_ZEPHYR (1) 77 | #define MICROPY_PY_ZSENSOR (0) 78 | #define MICROPY_PY_SYS_MODULES (0) 79 | #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) 80 | #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) 81 | #define MICROPY_PY_BUILTINS_COMPLEX (0) 82 | 83 | // Saving extra crumbs to make sure binary fits in 128K 84 | #define MICROPY_COMP_CONST_FOLDING (0) 85 | #define MICROPY_COMP_CONST (0) 86 | #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) 87 | 88 | #define MICROPY_PY_SYS_PLATFORM "zephyr" 89 | 90 | #ifdef CONFIG_BOARD 91 | #define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD 92 | #else 93 | #define MICROPY_HW_BOARD_NAME "zephyr-generic" 94 | #endif 95 | 96 | #ifdef CONFIG_SOC 97 | #define MICROPY_HW_MCU_NAME CONFIG_SOC 98 | #else 99 | #define MICROPY_HW_MCU_NAME "unknown-cpu" 100 | #endif 101 | 102 | #define MICROPY_MODULE_FROZEN_STR (1) 103 | 104 | typedef int mp_int_t; // must be pointer size 105 | typedef unsigned mp_uint_t; // must be pointer size 106 | typedef long mp_off_t; 107 | 108 | #define MP_STATE_PORT MP_STATE_VM 109 | 110 | #define MICROPY_PORT_ROOT_POINTERS \ 111 | const char *readline_hist[8]; 112 | 113 | extern const struct _mp_obj_module_t mp_module_machine; 114 | extern const struct _mp_obj_module_t mp_module_time; 115 | extern const struct _mp_obj_module_t mp_module_usocket; 116 | extern const struct _mp_obj_module_t mp_module_zephyr; 117 | extern const struct _mp_obj_module_t mp_module_zsensor; 118 | extern const struct _mp_obj_module_t mp_module_degu; 119 | 120 | #if MICROPY_PY_USOCKET 121 | #define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, 122 | #define MICROPY_PY_USOCKET_WEAK_DEF { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, 123 | #else 124 | #define MICROPY_PY_USOCKET_DEF 125 | #define MICROPY_PY_USOCKET_WEAK_DEF 126 | #endif 127 | 128 | #if MICROPY_PY_UTIME 129 | #define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, 130 | #else 131 | #define MICROPY_PY_UTIME_DEF 132 | #endif 133 | 134 | #if MICROPY_PY_ZEPHYR 135 | #define MICROPY_PY_ZEPHYR_DEF { MP_ROM_QSTR(MP_QSTR_zephyr), MP_ROM_PTR(&mp_module_zephyr) }, 136 | #else 137 | #define MICROPY_PY_ZEPHYR_DEF 138 | #endif 139 | 140 | #if MICROPY_PY_ZSENSOR 141 | #define MICROPY_PY_ZSENSOR_DEF { MP_ROM_QSTR(MP_QSTR_zsensor), MP_ROM_PTR(&mp_module_zsensor) }, 142 | #else 143 | #define MICROPY_PY_ZSENSOR_DEF 144 | #endif 145 | 146 | #define MICROPY_PORT_BUILTIN_MODULES \ 147 | { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ 148 | MICROPY_PY_USOCKET_DEF \ 149 | MICROPY_PY_UTIME_DEF \ 150 | MICROPY_PY_ZEPHYR_DEF \ 151 | MICROPY_PY_ZSENSOR_DEF \ 152 | { MP_ROM_QSTR(MP_QSTR_degu), MP_ROM_PTR(&mp_module_degu) }, \ 153 | 154 | #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ 155 | { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ 156 | MICROPY_PY_USOCKET_WEAK_DEF \ 157 | 158 | // extra built in names to add to the global namespace 159 | #define MICROPY_PORT_BUILTINS \ 160 | 161 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | // -*- tab-width : 4 -*- 2 | /* 3 | * This file is part of the MicroPython project, http://micropython.org/ 4 | * 5 | * The MIT License (MIT) 6 | * 7 | * Copyright (c) 2013, 2014 Damien P. George 8 | * Copyright (c) 2016-2017 Linaro Limited 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #ifdef CONFIG_NETWORKING 34 | #include 35 | #endif 36 | 37 | #include "py/compile.h" 38 | #include "py/runtime.h" 39 | #include "py/repl.h" 40 | #include "py/gc.h" 41 | #include "py/stackctrl.h" 42 | #include "lib/utils/pyexec.h" 43 | #include "lib/mp-readline/readline.h" 44 | 45 | #ifdef TEST 46 | #include "lib/upytesthelper/upytesthelper.h" 47 | #include "lib/tinytest/tinytest.c" 48 | #include "lib/upytesthelper/upytesthelper.c" 49 | #include TEST 50 | #endif 51 | 52 | static char *stack_top; 53 | static char heap[MICROPY_HEAP_SIZE]; 54 | 55 | void init_zephyr(void) { 56 | // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap 57 | // network addresses. 58 | #if 0 59 | #ifdef CONFIG_NETWORKING 60 | if (net_if_get_default() == NULL) { 61 | // If there's no default networking interface, 62 | // there's nothing to configure. 63 | return; 64 | } 65 | #endif 66 | #ifdef CONFIG_NET_IPV4 67 | static struct in_addr in4addr_my = {{{192, 0, 2, 1}}}; 68 | net_if_ipv4_addr_add(net_if_get_default(), &in4addr_my, NET_ADDR_MANUAL, 0); 69 | static struct in_addr in4netmask_my = {{{255, 255, 255, 0}}}; 70 | net_if_ipv4_set_netmask(net_if_get_default(), &in4netmask_my); 71 | static struct in_addr in4gw_my = {{{192, 0, 2, 2}}}; 72 | net_if_ipv4_set_gw(net_if_get_default(), &in4gw_my); 73 | #endif 74 | #ifdef CONFIG_NET_IPV6 75 | // 2001:db8::1 76 | static struct in6_addr in6addr_my = {{{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; 77 | net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, NET_ADDR_MANUAL, 0); 78 | #endif 79 | #endif 80 | } 81 | 82 | int exec_from_buffer(char* buf, size_t len) { 83 | nlr_buf_t nlr; 84 | 85 | const mp_parse_input_kind_t input_kind = MP_PARSE_FILE_INPUT; 86 | mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, buf, len, 0); 87 | if (lex == NULL) { 88 | printf("MemoryError: lexer could not allocate memory\n"); 89 | return -1; 90 | } 91 | 92 | if (nlr_push(&nlr) == 0) { 93 | qstr source_name = lex->source_name; 94 | mp_parse_tree_t pn = mp_parse(lex, input_kind); 95 | mp_obj_t module_fun = mp_compile(&pn, source_name, MP_EMIT_OPT_NONE, true); 96 | mp_call_function_0(module_fun); 97 | nlr_pop(); 98 | } else { 99 | return -1; 100 | } 101 | return 0; 102 | } 103 | 104 | int bg_main(char *src, size_t len) { 105 | int stack_dummy; 106 | 107 | stack_top = (char*)&stack_dummy; 108 | mp_stack_set_top(stack_top); 109 | // Make MicroPython's stack limit somewhat smaller than full stack available 110 | mp_stack_set_limit(CONFIG_MAIN_STACK_SIZE - 512); 111 | 112 | init_zephyr(); 113 | 114 | #if MICROPY_ENABLE_GC 115 | gc_init(heap, heap + sizeof(heap)); 116 | #endif 117 | mp_init(); 118 | mp_obj_list_init(mp_sys_path, 0); 119 | mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) 120 | mp_obj_list_init(mp_sys_argv, 0); 121 | exec_from_buffer(src, len); 122 | return 0; 123 | } 124 | 125 | 126 | int real_main(void) { 127 | int stack_dummy; 128 | stack_top = (char*)&stack_dummy; 129 | mp_stack_set_top(stack_top); 130 | // Make MicroPython's stack limit somewhat smaller than full stack available 131 | mp_stack_set_limit(CONFIG_MAIN_STACK_SIZE - 512); 132 | 133 | init_zephyr(); 134 | 135 | #ifdef TEST 136 | static const char *argv[] = {"test"}; 137 | upytest_set_heap(heap, heap + sizeof(heap)); 138 | int r = tinytest_main(1, argv, groups); 139 | printf("status: %d\n", r); 140 | #endif 141 | 142 | soft_reset: 143 | #if MICROPY_ENABLE_GC 144 | gc_init(heap, heap + sizeof(heap)); 145 | #endif 146 | mp_init(); 147 | mp_obj_list_init(mp_sys_path, 0); 148 | mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) 149 | mp_obj_list_init(mp_sys_argv, 0); 150 | 151 | for (;;) { 152 | if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { 153 | if (pyexec_raw_repl() != 0) { 154 | break; 155 | } 156 | } else { 157 | if (pyexec_friendly_repl() != 0) { 158 | break; 159 | } 160 | } 161 | } 162 | 163 | printf("soft reboot\n"); 164 | goto soft_reset; 165 | 166 | return 0; 167 | } 168 | 169 | void gc_collect(void) { 170 | // WARNING: This gc_collect implementation doesn't try to get root 171 | // pointers from CPU registers, and thus may function incorrectly. 172 | void *dummy; 173 | gc_collect_start(); 174 | gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); 175 | gc_collect_end(); 176 | //gc_dump_info(); 177 | } 178 | 179 | mp_lexer_t *mp_lexer_new_from_file(const char *filename) { 180 | mp_raise_OSError(ENOENT); 181 | } 182 | 183 | mp_import_stat_t mp_import_stat(const char *path) { 184 | return MP_IMPORT_STAT_NO_EXIST; 185 | } 186 | 187 | mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { 188 | return mp_const_none; 189 | } 190 | MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); 191 | 192 | NORETURN void nlr_jump_fail(void *val) { 193 | while (1); 194 | } 195 | 196 | #ifndef NDEBUG 197 | void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { 198 | printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); 199 | __fatal_error("Assertion failed"); 200 | } 201 | #endif 202 | -------------------------------------------------------------------------------- /machine_i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Hiroaki OHSAWA 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "i2c.h" 28 | #include "py/runtime.h" 29 | #include "py/mphal.h" 30 | #include "modmachine.h" 31 | 32 | const mp_obj_base_t machine_i2c_obj_template = {&machine_i2c_type}; 33 | 34 | #define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } 35 | 36 | #define I2C_DEV "I2C_0" 37 | #define I2C_DEV_0 DT_I2C_0_NAME 38 | #define I2C_DEV_1 DT_I2C_1_NAME 39 | #include 40 | 41 | u32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_FAST); 42 | 43 | void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data) { 44 | if (MP_OBJ_IS_INT(o)) { 45 | tmp_data[0] = mp_obj_get_int(o); 46 | bufinfo->buf = tmp_data; 47 | bufinfo->len = 1; 48 | bufinfo->typecode = 'B'; 49 | } else { 50 | mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ); 51 | } 52 | } 53 | 54 | STATIC void pyb_i2c_read_into (struct device *dev, mp_arg_val_t *args, vstr_t *vstr) { 55 | //TODO: check init 56 | // get the buffer to receive into 57 | if (MP_OBJ_IS_INT(args[1].u_obj)) { 58 | // allocate a new bytearray of given length 59 | vstr_init_len(vstr, mp_obj_get_int(args[1].u_obj)); 60 | } else { 61 | // get the existing buffer 62 | mp_buffer_info_t bufinfo; 63 | mp_get_buffer_raise(args[1].u_obj, &bufinfo, MP_BUFFER_WRITE); 64 | vstr->buf = bufinfo.buf; 65 | vstr->len = bufinfo.len; 66 | } 67 | // receive the data 68 | 69 | //TODO:check error 70 | i2c_read(dev, (byte *)vstr->buf, vstr->len, args[0].u_int); 71 | } 72 | 73 | mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { 74 | // parse args 75 | enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; 76 | static const mp_arg_t allowed_args[] = { 77 | { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, 78 | { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, 79 | { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, 80 | { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT }, 81 | { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT }, 82 | }; 83 | mp_arg_val_t pargs[MP_ARRAY_SIZE(allowed_args)]; 84 | mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, pargs); 85 | 86 | // work out i2c bus 87 | machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t); 88 | int i2c_id = mp_obj_get_int(args[ARG_id]); 89 | 90 | switch (i2c_id){ 91 | case 0: 92 | self->dev = device_get_binding(I2C_DEV_0); 93 | break; 94 | case 1: 95 | self->dev = device_get_binding(I2C_DEV_1); 96 | break; 97 | default: 98 | mp_raise_ValueError("device not found"); 99 | break; 100 | } 101 | if (self->dev == NULL) { 102 | mp_raise_ValueError("device not found"); 103 | } 104 | 105 | self->base = machine_i2c_obj_template; 106 | self->i2c_channel = i2c_id; 107 | RAISE_ERRNO(i2c_configure(self->dev, i2c_cfg)); 108 | return (mp_obj_t)self; 109 | } 110 | 111 | STATIC void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 112 | machine_i2c_obj_t *self = self_in; 113 | mp_printf(print, "I2C%u", self->i2c_channel); 114 | } 115 | #include 116 | 117 | STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { 118 | machine_i2c_obj_t *self = self_in; 119 | mp_obj_t list = mp_obj_new_list(0, NULL); 120 | uint8_t addr = 0x0; 121 | char buf; 122 | 123 | for (addr = 0x0; addr <= 0x77; addr++) { 124 | if (!i2c_read(self->dev, &buf, 0, addr)) { 125 | mp_obj_list_append(list, mp_obj_new_int(addr)); 126 | } 127 | } 128 | return list; 129 | } 130 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_scan_obj, machine_i2c_scan); 131 | 132 | STATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { 133 | machine_i2c_obj_t *self = pos_args[0]; 134 | STATIC const mp_arg_t pyb_i2c_readfrom_args[] = { 135 | { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, 136 | { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, 137 | }; 138 | // parse args 139 | mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_args)]; 140 | mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_args, args); 141 | 142 | vstr_t vstr; 143 | pyb_i2c_read_into(self->dev, args, &vstr); 144 | // return the received data 145 | return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); 146 | } 147 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_obj, 1, machine_i2c_readfrom); 148 | 149 | STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { 150 | machine_i2c_obj_t *self = pos_args[0]; 151 | mp_buffer_info_t bufinfo; 152 | uint8_t data[1]; 153 | 154 | STATIC const mp_arg_t pyb_i2c_writeto_args[] = { 155 | { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, 156 | { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, 157 | { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, 158 | }; 159 | mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_writeto_args)]; 160 | mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_writeto_args, args); 161 | 162 | pyb_buf_get_for_send(args[1].u_obj, &bufinfo, data); 163 | if (i2c_write(self->dev, bufinfo.buf, bufinfo.len, args[0].u_int) < 0) { 164 | mp_raise_ValueError("write failure"); 165 | } 166 | 167 | return mp_obj_new_int(bufinfo.len); 168 | } 169 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_obj, 1, machine_i2c_writeto); 170 | 171 | 172 | STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { 173 | { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) }, 174 | { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) }, 175 | { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) }, 176 | }; 177 | 178 | STATIC MP_DEFINE_CONST_DICT(machine_i2c_locals_dict, machine_i2c_locals_dict_table); 179 | 180 | const mp_obj_type_t machine_i2c_type = { 181 | { &mp_type_type }, 182 | .name = MP_QSTR_I2C, 183 | .print = machine_i2c_print, 184 | .make_new = machine_i2c_make_new, 185 | .locals_dict = (mp_obj_t)&machine_i2c_locals_dict, 186 | }; 187 | -------------------------------------------------------------------------------- /tools/imgtool/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | # Copyright 2017 Linaro Limited 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import click 18 | import getpass 19 | import imgtool.keys as keys 20 | from imgtool import image 21 | from imgtool.version import decode_version 22 | 23 | 24 | def gen_rsa2048(keyfile, passwd): 25 | keys.RSA2048.generate().export_private(path=keyfile, passwd=passwd) 26 | 27 | 28 | def gen_ecdsa_p256(keyfile, passwd): 29 | keys.ECDSA256P1.generate().export_private(keyfile, passwd=passwd) 30 | 31 | 32 | def gen_ecdsa_p224(keyfile, passwd): 33 | print("TODO: p-224 not yet implemented") 34 | 35 | 36 | valid_langs = ['c', 'rust'] 37 | keygens = { 38 | 'rsa-2048': gen_rsa2048, 39 | 'ecdsa-p256': gen_ecdsa_p256, 40 | 'ecdsa-p224': gen_ecdsa_p224, 41 | } 42 | 43 | 44 | def load_key(keyfile): 45 | # TODO: better handling of invalid pass-phrase 46 | key = keys.load(keyfile) 47 | if key is not None: 48 | return key 49 | passwd = getpass.getpass("Enter key passphrase: ").encode('utf-8') 50 | return keys.load(keyfile, passwd) 51 | 52 | 53 | def get_password(): 54 | while True: 55 | passwd = getpass.getpass("Enter key passphrase: ") 56 | passwd2 = getpass.getpass("Reenter passphrase: ") 57 | if passwd == passwd2: 58 | break 59 | print("Passwords do not match, try again") 60 | 61 | # Password must be bytes, always use UTF-8 for consistent 62 | # encoding. 63 | return passwd.encode('utf-8') 64 | 65 | 66 | @click.option('-p', '--password', is_flag=True, 67 | help='Prompt for password to protect key') 68 | @click.option('-t', '--type', metavar='type', required=True, 69 | type=click.Choice(keygens.keys())) 70 | @click.option('-k', '--key', metavar='filename', required=True) 71 | @click.command(help='Generate pub/private keypair') 72 | def keygen(type, key, password): 73 | password = get_password() if password else None 74 | keygens[type](key, password) 75 | 76 | 77 | @click.option('-l', '--lang', metavar='lang', default=valid_langs[0], 78 | type=click.Choice(valid_langs)) 79 | @click.option('-k', '--key', metavar='filename', required=True) 80 | @click.command(help='Get public key from keypair') 81 | def getpub(key, lang): 82 | key = load_key(key) 83 | if key is None: 84 | print("Invalid passphrase") 85 | elif lang == 'c': 86 | key.emit_c() 87 | elif lang == 'rust': 88 | key.emit_rust() 89 | else: 90 | raise ValueError("BUG: should never get here!") 91 | 92 | 93 | def validate_version(ctx, param, value): 94 | try: 95 | decode_version(value) 96 | return value 97 | except ValueError as e: 98 | raise click.BadParameter("{}".format(e)) 99 | 100 | 101 | def validate_header_size(ctx, param, value): 102 | min_hdr_size = image.IMAGE_HEADER_SIZE 103 | if value < min_hdr_size: 104 | raise click.BadParameter( 105 | "Minimum value for -H/--header-size is {}".format(min_hdr_size)) 106 | return value 107 | 108 | 109 | class BasedIntParamType(click.ParamType): 110 | name = 'integer' 111 | 112 | def convert(self, value, param, ctx): 113 | try: 114 | if value[:2].lower() == '0x': 115 | return int(value[2:], 16) 116 | elif value[:1] == '0': 117 | return int(value, 8) 118 | return int(value, 10) 119 | except ValueError: 120 | self.fail('%s is not a valid integer' % value, param, ctx) 121 | 122 | 123 | @click.argument('outfile') 124 | @click.argument('infile') 125 | @click.option('-E', '--encrypt', metavar='filename', 126 | help='Encrypt image using the provided public key') 127 | @click.option('-e', '--endian', type=click.Choice(['little', 'big']), 128 | default='little', help="Select little or big endian") 129 | @click.option('--overwrite-only', default=False, is_flag=True, 130 | help='Use overwrite-only instead of swap upgrades') 131 | @click.option('-M', '--max-sectors', type=int, 132 | help='When padding allow for this amount of sectors (defaults to 128)') 133 | @click.option('--pad', default=False, is_flag=True, 134 | help='Pad image to --slot-size bytes, adding trailer magic') 135 | @click.option('-S', '--slot-size', type=BasedIntParamType(), required=True, 136 | help='Size of the slot where the image will be written') 137 | @click.option('--pad-header', default=False, is_flag=True, 138 | help='Add --header-size zeroed bytes at the beginning of the image') 139 | @click.option('-H', '--header-size', callback=validate_header_size, 140 | type=BasedIntParamType(), required=True) 141 | @click.option('-v', '--version', callback=validate_version, required=True) 142 | @click.option('--align', type=click.Choice(['1', '2', '4', '8']), 143 | required=True) 144 | @click.option('-k', '--key', metavar='filename') 145 | @click.command(help='''Create a signed or unsigned image\n 146 | INFILE and OUTFILE are parsed as Intel HEX if the params have 147 | .hex extension, othewise binary format is used''') 148 | def sign(key, align, version, header_size, pad_header, slot_size, pad, 149 | max_sectors, overwrite_only, endian, encrypt, infile, outfile): 150 | img = image.Image(version=decode_version(version), header_size=header_size, 151 | pad_header=pad_header, pad=pad, align=int(align), 152 | slot_size=slot_size, max_sectors=max_sectors, 153 | overwrite_only=overwrite_only, endian=endian) 154 | img.load(infile) 155 | key = load_key(key) if key else None 156 | enckey = load_key(encrypt) if encrypt else None 157 | if enckey: 158 | if not isinstance(enckey, (keys.RSA2048, keys.RSA2048Public)): 159 | raise Exception("Encryption only available with RSA") 160 | if key and not isinstance(key, (keys.RSA2048, keys.RSA2048Public)): 161 | raise Exception("Encryption with sign only available with RSA") 162 | img.create(key, enckey) 163 | img.save(outfile) 164 | 165 | 166 | class AliasesGroup(click.Group): 167 | 168 | _aliases = { 169 | "create": "sign", 170 | } 171 | 172 | def list_commands(self, ctx): 173 | cmds = [k for k in self.commands] 174 | aliases = [k for k in self._aliases] 175 | return sorted(cmds + aliases) 176 | 177 | def get_command(self, ctx, cmd_name): 178 | rv = click.Group.get_command(self, ctx, cmd_name) 179 | if rv is not None: 180 | return rv 181 | if cmd_name in self._aliases: 182 | return click.Group.get_command(self, ctx, self._aliases[cmd_name]) 183 | return None 184 | 185 | 186 | @click.command(cls=AliasesGroup, 187 | context_settings=dict(help_option_names=['-h', '--help'])) 188 | def imgtool(): 189 | pass 190 | 191 | 192 | imgtool.add_command(keygen) 193 | imgtool.add_command(getpub) 194 | imgtool.add_command(sign) 195 | 196 | 197 | if __name__ == '__main__': 198 | imgtool() 199 | -------------------------------------------------------------------------------- /machine_pin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2013, 2014, 2015 Damien P. George 7 | * Copyright (c) 2016 Linaro Limited 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include "py/runtime.h" 36 | #include "py/gc.h" 37 | #include "py/mphal.h" 38 | #include "modmachine.h" 39 | 40 | const mp_obj_base_t machine_pin_obj_template = {&machine_pin_type}; 41 | 42 | STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 43 | machine_pin_obj_t *self = self_in; 44 | mp_printf(print, "", self->port, self->pin); 45 | } 46 | 47 | // pin.init(mode, pull=None, *, value) 48 | 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) { 49 | enum { ARG_mode, ARG_pull, ARG_value }; 50 | static const mp_arg_t allowed_args[] = { 51 | { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, 52 | { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, 53 | { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, 54 | }; 55 | 56 | // parse args 57 | mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; 58 | mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); 59 | 60 | // get io mode 61 | uint mode = args[ARG_mode].u_int; 62 | 63 | // get pull mode 64 | uint pull = GPIO_PUD_NORMAL; 65 | if (args[ARG_pull].u_obj != mp_const_none) { 66 | pull = mp_obj_get_int(args[ARG_pull].u_obj); 67 | } 68 | 69 | int ret = gpio_pin_configure(self->port, self->pin, mode | pull); 70 | if (ret) { 71 | mp_raise_ValueError("invalid pin"); 72 | } 73 | 74 | // get initial value 75 | if (args[ARG_value].u_obj != MP_OBJ_NULL) { 76 | (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[ARG_value].u_obj)); 77 | } 78 | 79 | return mp_const_none; 80 | } 81 | 82 | // constructor(drv_name, pin, ...) 83 | 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) { 84 | mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); 85 | 86 | // get the wanted port 87 | if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { 88 | mp_raise_ValueError("Pin id must be tuple of (\"GPIO_x\", pin#)"); 89 | } 90 | mp_obj_t *items; 91 | mp_obj_get_array_fixed_n(args[0], 2, &items); 92 | const char *drv_name = mp_obj_str_get_str(items[0]); 93 | int wanted_pin = mp_obj_get_int(items[1]); 94 | struct device *wanted_port = device_get_binding(drv_name); 95 | if (!wanted_port) { 96 | mp_raise_ValueError("invalid port"); 97 | } 98 | 99 | machine_pin_obj_t *pin = m_new_obj(machine_pin_obj_t); 100 | pin->base = machine_pin_obj_template; 101 | pin->port = wanted_port; 102 | pin->pin = wanted_pin; 103 | 104 | if (n_args > 1 || n_kw > 0) { 105 | // pin mode given, so configure this GPIO 106 | mp_map_t kw_args; 107 | mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); 108 | machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); 109 | } 110 | 111 | return (mp_obj_t)pin; 112 | } 113 | 114 | // fast method for getting/setting pin value 115 | 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) { 116 | mp_arg_check_num(n_args, n_kw, 0, 1, false); 117 | machine_pin_obj_t *self = self_in; 118 | if (n_args == 0) { 119 | u32_t pin_val; 120 | (void)gpio_pin_read(self->port, self->pin, &pin_val); 121 | return MP_OBJ_NEW_SMALL_INT(pin_val); 122 | } else { 123 | (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[0])); 124 | return mp_const_none; 125 | } 126 | } 127 | 128 | // pin.init(mode, pull) 129 | STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { 130 | return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); 131 | } 132 | MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); 133 | 134 | // pin.value([value]) 135 | STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { 136 | return machine_pin_call(args[0], n_args - 1, 0, args + 1); 137 | } 138 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); 139 | 140 | STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) { 141 | machine_pin_obj_t *self = self_in; 142 | (void)gpio_pin_write(self->port, self->pin, 0); 143 | return mp_const_none; 144 | } 145 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off); 146 | 147 | STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) { 148 | machine_pin_obj_t *self = self_in; 149 | (void)gpio_pin_write(self->port, self->pin, 1); 150 | return mp_const_none; 151 | } 152 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on); 153 | 154 | STATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { 155 | (void)errcode; 156 | machine_pin_obj_t *self = self_in; 157 | 158 | switch (request) { 159 | case MP_PIN_READ: { 160 | u32_t pin_val; 161 | gpio_pin_read(self->port, self->pin, &pin_val); 162 | return pin_val; 163 | } 164 | case MP_PIN_WRITE: { 165 | gpio_pin_write(self->port, self->pin, arg); 166 | return 0; 167 | } 168 | } 169 | return -1; 170 | } 171 | 172 | STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { 173 | // instance methods 174 | { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, 175 | { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, 176 | { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) }, 177 | { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) }, 178 | 179 | // class constants 180 | { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DIR_IN) }, 181 | { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DIR_OUT) }, 182 | { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PUD_PULL_UP) }, 183 | { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PUD_PULL_DOWN) }, 184 | }; 185 | 186 | STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); 187 | 188 | STATIC const mp_pin_p_t machine_pin_pin_p = { 189 | .ioctl = machine_pin_ioctl, 190 | }; 191 | 192 | const mp_obj_type_t machine_pin_type = { 193 | { &mp_type_type }, 194 | .name = MP_QSTR_Pin, 195 | .print = machine_pin_print, 196 | .make_new = mp_pin_make_new, 197 | .call = machine_pin_call, 198 | .protocol = &machine_pin_pin_p, 199 | .locals_dict = (mp_obj_t)&machine_pin_locals_dict, 200 | }; 201 | -------------------------------------------------------------------------------- /zcoap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include "py/nlr.h" 27 | #include "py/obj.h" 28 | #include "py/runtime.h" 29 | #include "py/binary.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include "zcoap.h" 43 | 44 | #define COAP_ACK_TIMEOUT_SEC 2 45 | #define COAP_MAX_RETRANSMIT 5 46 | 47 | LOG_MODULE_REGISTER(zcoap); 48 | 49 | static struct coap_block_context blk_ctx; 50 | 51 | static u8_t token[8]; 52 | 53 | static const u16_t COAP_BLOCK_THRESHOLD = 1024; 54 | 55 | static int zcoap_request(int sock, u8_t *path, u8_t method, u8_t *payload, u16_t *payload_len, bool *last_block) 56 | { 57 | int r; 58 | int rcvd; 59 | fd_set fds; 60 | struct coap_packet request; 61 | struct coap_packet reply; 62 | u8_t *data; 63 | const u8_t *payload_buf; 64 | int code; 65 | struct timeval tv; 66 | u8_t retry; 67 | long select_second; 68 | 69 | code = 0; 70 | retry = 0; 71 | 72 | if (blk_ctx.total_size == 0) { 73 | if (method == COAP_METHOD_GET) { 74 | coap_block_transfer_init(&blk_ctx, COAP_BLOCK_1024, 75 | BLOCK_WISE_TRANSFER_SIZE_GET); 76 | } 77 | else if ((method == COAP_METHOD_POST || method == COAP_METHOD_PUT) && 78 | *payload_len > COAP_BLOCK_THRESHOLD) { 79 | r = coap_block_transfer_init(&blk_ctx, COAP_BLOCK_1024, *payload_len); 80 | if (r != 0) { 81 | LOG_ERR("failed to coap_block_transfer_init(%d)\n", r); 82 | return code; 83 | } 84 | } 85 | memcpy(token, coap_next_token(), sizeof(token)); 86 | } 87 | 88 | data = (u8_t *)k_malloc(MAX_COAP_MSG_LEN); 89 | if (!data) { 90 | LOG_ERR("can't malloc\n"); 91 | memset(&blk_ctx, 0, sizeof(blk_ctx)); 92 | return code; 93 | } 94 | memset(data, 0, MAX_COAP_MSG_LEN); 95 | 96 | r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, 97 | 1, COAP_TYPE_CON, sizeof(token), token, 98 | method, coap_next_id()); 99 | if (r < 0) { 100 | LOG_ERR("Unable to init CoAP packet\n"); 101 | goto errorend; 102 | } 103 | 104 | r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, path, strlen(path)); 105 | if (r < 0) { 106 | LOG_ERR("Unable to append URI to request\n"); 107 | goto errorend; 108 | } 109 | 110 | if (method == COAP_METHOD_GET) { 111 | r = coap_append_block2_option(&request, &blk_ctx); 112 | if (r < 0) { 113 | LOG_ERR("Unable to append block2 option to request\n"); 114 | goto errorend; 115 | } 116 | } 117 | else if (method == COAP_METHOD_POST || method == COAP_METHOD_PUT) { 118 | if (*payload_len > COAP_BLOCK_THRESHOLD || blk_ctx.total_size != 0) { 119 | r = coap_append_block1_option(&request, &blk_ctx); 120 | if (r < 0) { 121 | LOG_ERR("Unable to append block1 option to request\n"); 122 | goto errorend; 123 | } 124 | } 125 | r = coap_packet_append_payload_marker(&request); 126 | if (r < 0) { 127 | LOG_ERR("Unable to append payload maker\n"); 128 | goto errorend; 129 | } 130 | 131 | if (blk_ctx.total_size > COAP_BLOCK_THRESHOLD) { 132 | if ((blk_ctx.total_size - blk_ctx.current) < COAP_BLOCK_THRESHOLD) { 133 | r = coap_packet_append_payload(&request, payload, 134 | blk_ctx.total_size - blk_ctx.current); 135 | } else { 136 | r = coap_packet_append_payload(&request, payload, COAP_BLOCK_THRESHOLD); 137 | } 138 | } 139 | else { 140 | r = coap_packet_append_payload(&request, payload, *payload_len); 141 | } 142 | if (r < 0) { 143 | LOG_ERR("Unable to append payload\n"); 144 | goto errorend; 145 | } 146 | } 147 | 148 | /* dummy read */ 149 | while(1) { 150 | rcvd = recv(sock, data, MAX_COAP_MSG_LEN, MSG_DONTWAIT); 151 | if (rcvd <= 0) { 152 | break; 153 | } 154 | } 155 | 156 | select_second = COAP_ACK_TIMEOUT_SEC; 157 | while (1) { 158 | r = send(sock, request.data, request.offset, 0); 159 | if (r < 0) { 160 | LOG_ERR("Unable to send request\n"); 161 | goto errorend; 162 | } 163 | 164 | FD_ZERO(&fds); 165 | FD_SET(sock, &fds); 166 | tv.tv_sec = select_second; 167 | tv.tv_usec = 0; 168 | r = select(sock + 1, &fds, NULL, NULL, &tv); 169 | if (!r) { 170 | select_second *= 2; 171 | LOG_ERR("Receiving response timeout:next %ld second", 172 | select_second); 173 | retry ++; 174 | } 175 | else{ 176 | break; 177 | } 178 | 179 | if (retry > COAP_MAX_RETRANSMIT) { 180 | code = COAP_FAILED_TO_RECEIVE_RESPONSE; 181 | LOG_ERR("Retry out\n"); 182 | goto errorend; 183 | } 184 | } 185 | 186 | rcvd = recv(sock, data, MAX_COAP_MSG_LEN, MSG_DONTWAIT); 187 | if (rcvd == 0) { 188 | LOG_ERR("Unable to receive response\n"); 189 | goto errorend; 190 | } 191 | if (rcvd < 0) { 192 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 193 | r = 0; 194 | } 195 | else { 196 | LOG_ERR("Unable to receive response\n"); 197 | r = -errno; 198 | } 199 | 200 | goto errorend; 201 | } 202 | 203 | r = coap_packet_parse(&reply, data, rcvd, NULL, 0); 204 | if (r < 0) { 205 | LOG_ERR("Unable to parse recieved packet\n"); 206 | goto errorend; 207 | } 208 | 209 | code = coap_header_get_code(&reply); 210 | 211 | if (method == COAP_METHOD_GET) { 212 | payload_buf = coap_packet_get_payload(&reply, payload_len); 213 | memcpy(payload, payload_buf, *payload_len); 214 | 215 | if (!coap_next_block(&reply, &blk_ctx) || code != COAP_RESPONSE_CODE_CONTENT) { 216 | memset(&blk_ctx, 0, sizeof(blk_ctx)); 217 | *last_block = true; 218 | } 219 | else { 220 | *last_block = false; 221 | } 222 | } 223 | else if (method == COAP_METHOD_POST || method == COAP_METHOD_PUT) { 224 | if (blk_ctx.total_size > COAP_BLOCK_THRESHOLD) { 225 | r = coap_next_block(&request, &blk_ctx); 226 | if (r >= *payload_len || r == 0) { 227 | memset(&blk_ctx, 0, sizeof(blk_ctx)); 228 | *last_block = true; 229 | } 230 | else { 231 | *last_block = false; 232 | } 233 | } 234 | else { 235 | memset(&blk_ctx, 0, sizeof(blk_ctx)); 236 | *last_block = true; 237 | } 238 | } 239 | 240 | k_free(data); 241 | return code; 242 | 243 | errorend: 244 | memset(&blk_ctx, 0, sizeof(blk_ctx)); 245 | k_free(data); 246 | return code; 247 | } 248 | 249 | int zcoap_request_post(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block) 250 | { 251 | return zcoap_request(sock, path, COAP_METHOD_POST, payload, payload_len, last_block); 252 | } 253 | 254 | int zcoap_request_put(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block) 255 | { 256 | return zcoap_request(sock, path, COAP_METHOD_PUT, payload, payload_len, last_block); 257 | } 258 | 259 | int zcoap_request_get(int sock, u8_t *path, u8_t *payload, u16_t *payload_len, bool *last_block) 260 | { 261 | return zcoap_request(sock, path, COAP_METHOD_GET, payload, payload_len, last_block); 262 | } 263 | 264 | int zcoap_request_delete(int sock, u8_t *path) 265 | { 266 | return zcoap_request(sock, path, COAP_METHOD_DELETE, NULL, NULL, NULL); 267 | } 268 | -------------------------------------------------------------------------------- /tools/imgtool/image.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Nordic Semiconductor ASA 2 | # Copyright 2017 Linaro Limited 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | """ 17 | Image signing and management. 18 | """ 19 | 20 | from . import version as versmod 21 | from intelhex import IntelHex 22 | import hashlib 23 | import struct 24 | import os.path 25 | from cryptography.hazmat.primitives.asymmetric import padding 26 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 27 | from cryptography.hazmat.backends import default_backend 28 | from cryptography.hazmat.primitives import hashes 29 | 30 | IMAGE_MAGIC = 0x96f3b83d 31 | IMAGE_HEADER_SIZE = 32 32 | BIN_EXT = "bin" 33 | INTEL_HEX_EXT = "hex" 34 | DEFAULT_MAX_SECTORS = 128 35 | 36 | # Image header flags. 37 | IMAGE_F = { 38 | 'PIC': 0x0000001, 39 | 'NON_BOOTABLE': 0x0000010, 40 | 'ENCRYPTED': 0x0000004, 41 | } 42 | 43 | TLV_VALUES = { 44 | 'KEYHASH': 0x01, 45 | 'SHA256': 0x10, 46 | 'RSA2048': 0x20, 47 | 'ECDSA224': 0x21, 48 | 'ECDSA256': 0x22, 49 | 'ENCRSA2048': 0x30, 50 | 'ENCKW128': 0x31, 51 | } 52 | 53 | TLV_INFO_SIZE = 4 54 | TLV_INFO_MAGIC = 0x6907 55 | 56 | boot_magic = bytes([ 57 | 0x77, 0xc2, 0x95, 0xf3, 58 | 0x60, 0xd2, 0xef, 0x7f, 59 | 0x35, 0x52, 0x50, 0x0f, 60 | 0x2c, 0xb6, 0x79, 0x80, ]) 61 | 62 | STRUCT_ENDIAN_DICT = { 63 | 'little': '<', 64 | 'big': '>' 65 | } 66 | 67 | class TLV(): 68 | def __init__(self, endian): 69 | self.buf = bytearray() 70 | self.endian = endian 71 | 72 | def add(self, kind, payload): 73 | """Add a TLV record. Kind should be a string found in TLV_VALUES above.""" 74 | e = STRUCT_ENDIAN_DICT[self.endian] 75 | buf = struct.pack(e + 'BBH', TLV_VALUES[kind], 0, len(payload)) 76 | self.buf += buf 77 | self.buf += payload 78 | 79 | def get(self): 80 | e = STRUCT_ENDIAN_DICT[self.endian] 81 | header = struct.pack(e + 'HH', TLV_INFO_MAGIC, TLV_INFO_SIZE + len(self.buf)) 82 | return header + bytes(self.buf) 83 | 84 | 85 | class Image(): 86 | 87 | def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, 88 | pad_header=False, pad=False, align=1, slot_size=0, 89 | max_sectors=DEFAULT_MAX_SECTORS, overwrite_only=False, 90 | endian="little"): 91 | self.version = version or versmod.decode_version("0") 92 | self.header_size = header_size 93 | self.pad_header = pad_header 94 | self.pad = pad 95 | self.align = align 96 | self.slot_size = slot_size 97 | self.max_sectors = max_sectors 98 | self.overwrite_only = overwrite_only 99 | self.endian = endian 100 | self.base_addr = None 101 | self.payload = [] 102 | 103 | def __repr__(self): 104 | return "".format( 107 | self.version, 108 | self.header_size, 109 | self.base_addr if self.base_addr is not None else "N/A", 110 | self.align, 111 | self.slot_size, 112 | self.max_sectors, 113 | self.overwrite_only, 114 | self.endian, 115 | self.__class__.__name__, 116 | len(self.payload)) 117 | 118 | def load(self, path): 119 | """Load an image from a given file""" 120 | ext = os.path.splitext(path)[1][1:].lower() 121 | if ext == INTEL_HEX_EXT: 122 | ih = IntelHex(path) 123 | self.payload = ih.tobinarray() 124 | self.base_addr = ih.minaddr() 125 | else: 126 | with open(path, 'rb') as f: 127 | self.payload = f.read() 128 | 129 | # Add the image header if needed. 130 | if self.pad_header and self.header_size > 0: 131 | if self.base_addr: 132 | # Adjust base_addr for new header 133 | self.base_addr -= self.header_size 134 | self.payload = (b'\000' * self.header_size) + self.payload 135 | 136 | self.check() 137 | 138 | def save(self, path): 139 | """Save an image from a given file""" 140 | if self.pad: 141 | self.pad_to(self.slot_size) 142 | 143 | ext = os.path.splitext(path)[1][1:].lower() 144 | if ext == INTEL_HEX_EXT: 145 | # input was in binary format, but HEX needs to know the base addr 146 | if self.base_addr is None: 147 | raise Exception("Input file does not provide a base address") 148 | h = IntelHex() 149 | h.frombytes(bytes=self.payload, offset=self.base_addr) 150 | h.tofile(path, 'hex') 151 | else: 152 | with open(path, 'wb') as f: 153 | f.write(self.payload) 154 | 155 | def check(self): 156 | """Perform some sanity checking of the image.""" 157 | # If there is a header requested, make sure that the image 158 | # starts with all zeros. 159 | if self.header_size > 0: 160 | if any(v != 0 for v in self.payload[0:self.header_size]): 161 | raise Exception("Padding requested, but image does not start with zeros") 162 | if self.slot_size > 0: 163 | tsize = self._trailer_size(self.align, self.max_sectors, 164 | self.overwrite_only) 165 | padding = self.slot_size - (len(self.payload) + tsize) 166 | if padding < 0: 167 | msg = "Image size (0x{:x}) + trailer (0x{:x}) exceeds requested size 0x{:x}".format( 168 | len(self.payload), tsize, self.slot_size) 169 | raise Exception(msg) 170 | 171 | def create(self, key, enckey): 172 | self.add_header(enckey) 173 | 174 | tlv = TLV(self.endian) 175 | 176 | # Note that ecdsa wants to do the hashing itself, which means 177 | # we get to hash it twice. 178 | sha = hashlib.sha256() 179 | sha.update(self.payload) 180 | digest = sha.digest() 181 | 182 | tlv.add('SHA256', digest) 183 | 184 | if key is not None: 185 | pub = key.get_public_bytes() 186 | sha = hashlib.sha256() 187 | sha.update(pub) 188 | pubbytes = sha.digest() 189 | tlv.add('KEYHASH', pubbytes) 190 | 191 | sig = key.sign(bytes(self.payload)) 192 | tlv.add(key.sig_tlv(), sig) 193 | 194 | if enckey is not None: 195 | plainkey = os.urandom(16) 196 | cipherkey = enckey._get_public().encrypt( 197 | plainkey, padding.OAEP( 198 | mgf=padding.MGF1(algorithm=hashes.SHA256()), 199 | algorithm=hashes.SHA256(), 200 | label=None)) 201 | tlv.add('ENCRSA2048', cipherkey) 202 | 203 | nonce = bytes([0] * 16) 204 | cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce), 205 | backend=default_backend()) 206 | encryptor = cipher.encryptor() 207 | img = bytes(self.payload[self.header_size:]) 208 | self.payload[self.header_size:] = encryptor.update(img) + \ 209 | encryptor.finalize() 210 | 211 | self.payload += tlv.get() 212 | 213 | def add_header(self, enckey): 214 | """Install the image header.""" 215 | 216 | flags = 0 217 | if enckey is not None: 218 | flags |= IMAGE_F['ENCRYPTED'] 219 | 220 | e = STRUCT_ENDIAN_DICT[self.endian] 221 | fmt = (e + 222 | # type ImageHdr struct { 223 | 'I' + # Magic uint32 224 | 'I' + # LoadAddr uint32 225 | 'H' + # HdrSz uint16 226 | 'H' + # Pad1 uint16 227 | 'I' + # ImgSz uint32 228 | 'I' + # Flags uint32 229 | 'BBHI' + # Vers ImageVersion 230 | 'I' # Pad2 uint32 231 | ) # } 232 | assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE 233 | header = struct.pack(fmt, 234 | IMAGE_MAGIC, 235 | 0, # LoadAddr 236 | self.header_size, 237 | 0, # Pad1 238 | len(self.payload) - self.header_size, # ImageSz 239 | flags, # Flags 240 | self.version.major, 241 | self.version.minor or 0, 242 | self.version.revision or 0, 243 | self.version.build or 0, 244 | 0) # Pad2 245 | self.payload = bytearray(self.payload) 246 | self.payload[:len(header)] = header 247 | 248 | def _trailer_size(self, write_size, max_sectors, overwrite_only): 249 | # NOTE: should already be checked by the argument parser 250 | if overwrite_only: 251 | return 8 * 2 + 16 252 | else: 253 | if write_size not in set([1, 2, 4, 8]): 254 | raise Exception("Invalid alignment: {}".format(write_size)) 255 | m = DEFAULT_MAX_SECTORS if max_sectors is None else max_sectors 256 | return m * 3 * write_size + 8 * 2 + 16 257 | 258 | def pad_to(self, size): 259 | """Pad the image to the given size, with the given flash alignment.""" 260 | tsize = self._trailer_size(self.align, self.max_sectors, 261 | self.overwrite_only) 262 | padding = size - (len(self.payload) + tsize) 263 | pbytes = b'\xff' * padding 264 | pbytes += b'\xff' * (tsize - len(boot_magic)) 265 | pbytes += boot_magic 266 | self.payload += pbytes 267 | -------------------------------------------------------------------------------- /machine_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Atmark Techno, Inc. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | #include "uart.h" 29 | #include "py/runtime.h" 30 | #include "py/mphal.h" 31 | #include "py/stream.h" 32 | #include "modmachine.h" 33 | 34 | const mp_obj_base_t machine_uart_obj_template = {&machine_uart_type}; 35 | 36 | #define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } 37 | #define UART_DEV_0 DT_UART_0_NAME 38 | #define UART_0 0 39 | 40 | enum {ARG_baudrate, ARG_bits, ARG_parity, ARG_stop }; 41 | STATIC const char *_parity_name[] = {"None","ODD","Even"}; 42 | 43 | #define BUF_SIZE 4096 44 | u8_t uart_rxbuffer[BUF_SIZE]; 45 | volatile int uart_rxbuf_write_cursor = 0; 46 | volatile int uart_rxbuf_read_cursor = 0; 47 | u8_t uart_txbuffer[BUF_SIZE]; 48 | volatile int uart_txbuf_write_cursor = 0; 49 | volatile int uart_txbuf_read_cursor = 0; 50 | 51 | static void uart_cb(struct device *dev){ 52 | uart_irq_update(dev); 53 | if(uart_irq_rx_ready(dev)){ 54 | uart_fifo_read(dev, (u8_t *)&uart_rxbuffer[uart_rxbuf_write_cursor], 1); 55 | uart_rxbuf_write_cursor = (uart_rxbuf_write_cursor + 1) % BUF_SIZE; 56 | if(uart_rxbuf_write_cursor == uart_rxbuf_read_cursor){ 57 | uart_rxbuf_read_cursor = (uart_rxbuf_read_cursor + 1) % BUF_SIZE; 58 | } 59 | } 60 | 61 | if(uart_irq_tx_ready(dev) && (uart_txbuf_read_cursor != uart_txbuf_write_cursor)){ 62 | uart_fifo_fill(dev, (u8_t *)&uart_txbuffer[uart_txbuf_read_cursor], 1); 63 | uart_txbuf_read_cursor = (uart_txbuf_read_cursor + 1) % BUF_SIZE; 64 | if(uart_txbuf_read_cursor == uart_txbuf_write_cursor){ 65 | while(1){ 66 | if(uart_irq_tx_complete(dev)){ 67 | uart_irq_tx_disable(dev); 68 | break; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | static int uart_read_bytes(u8_t* data, int size){ 76 | int read_size = 0; 77 | 78 | unsigned int key; 79 | while(1){ 80 | if(uart_rxbuf_read_cursor != uart_rxbuf_write_cursor){ 81 | key = irq_lock(); 82 | *data = uart_rxbuffer[uart_rxbuf_read_cursor]; 83 | uart_rxbuf_read_cursor = (uart_rxbuf_read_cursor + 1) % BUF_SIZE; 84 | read_size ++; 85 | data ++; 86 | irq_unlock(key); 87 | } 88 | else{ 89 | ; 90 | } 91 | 92 | if(size <= read_size){ 93 | break; 94 | } 95 | } 96 | return read_size; 97 | } 98 | 99 | static int uart_write_bytes(const u8_t* data, int size){ 100 | int write_size = 0; 101 | for(write_size=0; write_size < size; write_size++){ 102 | uart_txbuffer[uart_txbuf_write_cursor] = *data; 103 | uart_txbuf_write_cursor = (uart_txbuf_write_cursor + 1) % BUF_SIZE; 104 | data++; 105 | if(uart_txbuf_write_cursor == uart_txbuf_read_cursor){ 106 | break; 107 | } 108 | } 109 | return write_size; 110 | } 111 | 112 | STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ 113 | static const mp_arg_t allowed_args[] = { 114 | { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, 115 | { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, 116 | { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, 117 | { MP_QSTR_stop, MP_ARG_INT , {.u_int = 0} } 118 | }; 119 | mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; 120 | mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); 121 | 122 | while(1){ 123 | if(uart_irq_tx_complete(self->dev)){ 124 | break; 125 | } 126 | } 127 | 128 | struct uart_config cfg; 129 | RAISE_ERRNO(uart_config_get(self->dev, &cfg)); 130 | 131 | if(args[ARG_baudrate].u_int > 0){ 132 | switch(args[ARG_baudrate].u_int){ 133 | case 1200: 134 | case 2400: 135 | case 4800: 136 | case 9600: 137 | case 14400: 138 | case 19200: 139 | case 28800: 140 | case 31250: 141 | case 38400: 142 | case 56000: 143 | case 57600: 144 | case 76800: 145 | case 115200: 146 | case 230400: 147 | case 250000: 148 | case 460800: 149 | case 921600: 150 | case 1000000: 151 | self->cfg.baudrate = args[ARG_baudrate].u_int; 152 | break; 153 | default : 154 | mp_raise_ValueError("invalid baudrate"); 155 | break; 156 | } 157 | } 158 | else{ 159 | self->cfg.baudrate = cfg.baudrate; 160 | } 161 | 162 | if(args[ARG_parity].u_obj != MP_OBJ_NULL){ 163 | if(args[ARG_parity].u_obj == mp_const_none){ 164 | self->cfg.parity = UART_CFG_PARITY_NONE; 165 | } 166 | else if(mp_obj_get_int(args[ARG_parity].u_obj) == 0){ 167 | self->cfg.parity = UART_CFG_PARITY_EVEN; 168 | } 169 | else{ 170 | mp_raise_ValueError("invalid parity"); 171 | } 172 | } 173 | else{ 174 | self->cfg.parity = cfg.parity; 175 | } 176 | 177 | if(args[ARG_stop].u_int != 0){ 178 | if(args[ARG_stop].u_int == 1){ 179 | self->cfg.stop_bits = UART_CFG_STOP_BITS_1; 180 | } 181 | else{ 182 | mp_raise_ValueError("invalid stop bits"); 183 | } 184 | } 185 | else{ 186 | self->cfg.stop_bits = cfg.stop_bits; 187 | } 188 | 189 | if(args[ARG_bits].u_int != 0){ 190 | if(args[ARG_bits].u_int == 8){ 191 | self->cfg.data_bits = UART_CFG_DATA_BITS_8; 192 | } 193 | else{ 194 | mp_raise_ValueError("invalid data bits"); 195 | } 196 | } 197 | else{ 198 | self->cfg.data_bits = cfg.data_bits; 199 | } 200 | self->cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE; 201 | 202 | RAISE_ERRNO(uart_configure(self->dev, &self->cfg)); 203 | } 204 | 205 | STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args){ 206 | mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); 207 | 208 | machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t); 209 | self->base = machine_uart_obj_template; 210 | 211 | int uart_id = mp_obj_get_int(args[0]); 212 | if(uart_id == UART_0){ 213 | self->dev = device_get_binding(UART_DEV_0); 214 | self->uart_channel = uart_id; 215 | } 216 | else{ 217 | mp_raise_ValueError("device not found"); 218 | } 219 | 220 | mp_map_t kw_args; 221 | mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); 222 | machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); 223 | 224 | uart_irq_callback_set(self->dev, uart_cb); 225 | uart_irq_rx_enable(self->dev); 226 | 227 | return (mp_obj_t)self; 228 | } 229 | 230 | STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { 231 | machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); 232 | return mp_const_none; 233 | } 234 | MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); 235 | 236 | STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 237 | machine_uart_obj_t *self = self_in; 238 | mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u)", 239 | self->uart_channel, self->cfg.baudrate, self->cfg.data_bits, _parity_name[self->cfg.parity], self->cfg.stop_bits); 240 | } 241 | 242 | STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in){ 243 | machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); 244 | while(1){ 245 | if(uart_irq_tx_complete(self->dev)){ 246 | uart_irq_tx_disable(self->dev); 247 | break; 248 | } 249 | } 250 | uart_irq_rx_disable(self->dev); 251 | 252 | return mp_const_none; 253 | } 254 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit); 255 | 256 | STATIC mp_obj_t machine_uart_any(mp_obj_t self_in){ 257 | size_t rxbufsize = 0; 258 | 259 | if(uart_rxbuf_write_cursor > uart_rxbuf_read_cursor){ 260 | rxbufsize = uart_rxbuf_write_cursor - uart_rxbuf_read_cursor; 261 | } 262 | else if(uart_rxbuf_write_cursor < uart_rxbuf_read_cursor){ 263 | rxbufsize = BUF_SIZE - (uart_rxbuf_read_cursor - uart_rxbuf_write_cursor); 264 | } 265 | return MP_OBJ_NEW_SMALL_INT(rxbufsize); 266 | } 267 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); 268 | 269 | STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { 270 | { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, 271 | { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) }, 272 | { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) }, 273 | { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, 274 | { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, 275 | { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, 276 | { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, 277 | }; 278 | 279 | STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); 280 | 281 | STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { 282 | int read_size = 0; 283 | if(size > 0){ 284 | read_size = uart_read_bytes(buf_in, size); 285 | if(read_size == 0){ 286 | *errcode = MP_EAGAIN; 287 | read_size = MP_STREAM_ERROR; 288 | } 289 | } 290 | return read_size; 291 | } 292 | 293 | STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { 294 | machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); 295 | int write_size = 0; 296 | if(size > 0){ 297 | write_size = uart_write_bytes(buf_in, size); 298 | uart_irq_tx_enable(self->dev); 299 | } 300 | return write_size; 301 | } 302 | 303 | STATIC const mp_stream_p_t uart_stream_p = { 304 | .read = machine_uart_read, 305 | .write = machine_uart_write, 306 | .ioctl = false, 307 | .is_text = false, 308 | }; 309 | 310 | const mp_obj_type_t machine_uart_type = { 311 | { &mp_type_type }, 312 | .name = MP_QSTR_UART, 313 | .print = machine_uart_print, 314 | .make_new = machine_uart_make_new, 315 | .protocol = &uart_stream_p, 316 | .locals_dict = (mp_obj_t)&machine_uart_locals_dict, 317 | }; 318 | 319 | -------------------------------------------------------------------------------- /degu_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Atmark Techno, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "zcoap.h" 33 | #include "degu_utils.h" 34 | 35 | #define I2C 36 | #include "libA71CH_api.h" 37 | 38 | extern char *net_byte_to_hex(char *ptr, u8_t byte, char base, bool pad); 39 | extern char *net_sprint_addr(sa_family_t af, const void *addr); 40 | 41 | void get_eui64(char *eui64) 42 | { 43 | struct net_if *iface; 44 | char *buf = eui64; 45 | char byte; 46 | int i; 47 | 48 | iface = net_if_get_by_index(1); 49 | 50 | for (i = 0; i < 8; i++) { 51 | byte = (char)net_if_get_link_addr(iface)->addr[i]; 52 | buf = net_byte_to_hex(buf, byte, 'A', true); 53 | (*buf)++; 54 | } 55 | } 56 | 57 | static char *get_gw_addr(unsigned int prefix) 58 | { 59 | struct net_if *iface; 60 | struct net_if_ipv6 *ipv6; 61 | struct net_if_addr *unicast; 62 | struct in6_addr gw_in6_addr; 63 | int i, j; 64 | 65 | iface = net_if_get_by_index(1); 66 | ipv6 = iface->config.ip.ipv6; 67 | 68 | for (i = 0; ipv6 && i < NET_IF_MAX_IPV6_ADDR; i++) { 69 | unicast = &ipv6->unicast[i]; 70 | 71 | if (!unicast->is_used) { 72 | continue; 73 | } 74 | 75 | if (unicast->address.in6_addr.s6_addr[0] == 0xfd) { 76 | for (j = 0; j < 16; j++) { 77 | gw_in6_addr.s6_addr[j] = unicast->address.in6_addr.s6_addr[j]; 78 | if (j >= prefix / 8) { 79 | gw_in6_addr.s6_addr[j] = 0x00; 80 | } 81 | } 82 | gw_in6_addr.s6_addr[15] += 1; 83 | return net_sprint_addr(AF_INET6, &gw_in6_addr); 84 | } 85 | } 86 | 87 | return NULL; 88 | } 89 | 90 | int degu_send_asset(void); 91 | int degu_connect(void); 92 | 93 | int degu_coap_request(u8_t *path, u8_t method, u8_t *payload, void (*callback)(u8_t *, u16_t)) 94 | { 95 | int sock; 96 | struct sockaddr_in6 sockaddr; 97 | u16_t payload_len; 98 | bool last_block = false; 99 | char gw_addr[NET_IPV6_ADDR_LEN]; 100 | char eui64[17]; 101 | char coap_path[40]; 102 | int ret; 103 | int code = 0; 104 | 105 | while (!net_if_is_up(net_if_get_by_index(1))); 106 | 107 | sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_DTLS_1_2); 108 | if (sock == -1) { 109 | goto end; 110 | } 111 | 112 | sockaddr.sin6_family = AF_INET6; 113 | 114 | strcpy(gw_addr, get_gw_addr(64)); 115 | ret = zsock_inet_pton(AF_INET6, gw_addr, &sockaddr.sin6_addr); 116 | if (ret <= 0) { 117 | goto end; 118 | } 119 | 120 | sockaddr.sin6_port = htons(COAPS_PORT); 121 | ret = zsock_connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); 122 | if (ret < 0) { 123 | goto end; 124 | } 125 | 126 | get_eui64(eui64); 127 | eui64[16] = '\0'; 128 | 129 | snprintf(coap_path, sizeof(coap_path), "%s/%s", path, eui64); 130 | 131 | while (1) { 132 | switch (method) { 133 | case COAP_METHOD_POST: 134 | payload_len = strlen((char*)payload); 135 | code = zcoap_request_post(sock, coap_path, payload, &payload_len, &last_block); 136 | break; 137 | case COAP_METHOD_PUT: 138 | payload_len = strlen((char*)payload); 139 | code = zcoap_request_put(sock, coap_path, payload, &payload_len, &last_block); 140 | break; 141 | case COAP_METHOD_GET: 142 | code = zcoap_request_get(sock, coap_path, payload, &payload_len, &last_block); 143 | break; 144 | case COAP_METHOD_DELETE: 145 | code = zcoap_request_delete(sock, coap_path); 146 | default: 147 | goto end; 148 | } 149 | 150 | /* Process by response code */ 151 | switch (code) { 152 | case COAP_RESPONSE_CODE_VALID: 153 | /* GW is in progress */ 154 | break; 155 | 156 | case COAP_RESPONSE_CODE_CONTENT: 157 | /* In progress of GET */ 158 | if (callback != NULL) { 159 | /* Process a block of payload*/ 160 | callback(payload, payload_len); 161 | } 162 | else { 163 | payload += 1024; 164 | } 165 | if (last_block) { 166 | goto end; 167 | } 168 | break; 169 | 170 | case COAP_RESPONSE_CODE_CONTINUE: 171 | /* In progress of PUT/POST */ 172 | if (last_block) { 173 | goto end; 174 | } 175 | payload += 1024; 176 | break; 177 | 178 | case COAP_RESPONSE_CODE_UNAUTHORIZED: 179 | /* illigal or expired certificate */ 180 | case COAP_RESPONSE_CODE_FORBIDDEN: 181 | /* invalid or duplex certificate */ 182 | degu_get_asset(); 183 | /* Need to send the asset again */ 184 | code = degu_send_asset(); 185 | if (code < COAP_RESPONSE_CODE_OK) { 186 | goto end; 187 | } 188 | /* Need to make connection again */ 189 | degu_connect(); 190 | code = COAP_FAILED_TO_RECEIVE_RESPONSE; 191 | goto end; 192 | break; 193 | 194 | case COAP_RESPONSE_CODE_BAD_REQUEST: 195 | case COAP_RESPONSE_CODE_INTERNAL_ERROR: 196 | degu_get_asset(); 197 | /* Need to send the asset again */ 198 | code = degu_send_asset(); 199 | if (code < COAP_RESPONSE_CODE_OK) { 200 | goto end; 201 | } 202 | 203 | case COAP_RESPONSE_CODE_GATEWAY_TIMEOUT: 204 | /* Need to make connection again */ 205 | code = degu_connect(); 206 | if (code < COAP_RESPONSE_CODE_OK) { 207 | goto end; 208 | } 209 | break; 210 | 211 | case COAP_RESPONSE_CODE_NOT_FOUND: 212 | if (method == COAP_METHOD_GET) { 213 | if (strstr(path, "x509") != NULL) { 214 | /* end procedure, if gw has no degu asset. */ 215 | goto end; 216 | } else if (strstr(path, "update") != NULL) { 217 | /* ota, bad url. */ 218 | code = COAP_FAILED_TO_RECEIVE_RESPONSE; 219 | goto end; 220 | } 221 | } 222 | 223 | /* Need to get the asset from GW again */ 224 | code = degu_get_asset(); 225 | if (code < COAP_RESPONSE_CODE_OK) { 226 | goto end; 227 | } 228 | break; 229 | 230 | default: 231 | /* Complete or failed the operation */ 232 | goto end; 233 | } 234 | } 235 | 236 | end: 237 | close(sock); 238 | 239 | return code; 240 | } 241 | 242 | /** 243 | * check A71CH has asset. 244 | * @return 1:has asset, 0:no asset 245 | */ 246 | static int a71ch_has_asset(void) 247 | { 248 | int hasAsset = 0; 249 | 250 | if (LIBA71CH_open() != 0) { 251 | return hasAsset; 252 | } 253 | 254 | if (LIBA71CH_hasKeyAndCert()) { 255 | hasAsset = 1; 256 | } 257 | 258 | LIBA71CH_finalize(); 259 | 260 | return hasAsset; 261 | 262 | } 263 | 264 | /** 265 | * update asset on A71CH. 266 | * @return 0:success, -1:fail 267 | */ 268 | static int a71ch_update_asset(const char *key, const char *cert) 269 | { 270 | int result = 0; 271 | int code_delete; 272 | if (LIBA71CH_open() != 0) { 273 | return -1; 274 | } 275 | 276 | if (LIBA71CH_eraseKeyAndCert() != 0) { 277 | result = -1; 278 | goto a71ch_end; 279 | } 280 | 281 | if (LIBA71CH_setKeyAndCert(key, cert)) { 282 | result = -1; 283 | goto a71ch_end; 284 | } 285 | 286 | /* send DELETE x509/key command, Degu GW delete key and cert both. */ 287 | code_delete = degu_coap_request("x509/key", COAP_METHOD_DELETE, NULL, NULL); 288 | if (code_delete < COAP_RESPONSE_CODE_OK) { 289 | result = -1; 290 | goto a71ch_end; 291 | } 292 | 293 | a71ch_end: 294 | LIBA71CH_finalize(); 295 | return result; 296 | } 297 | 298 | int degu_get_asset(void) 299 | { 300 | char *key; 301 | char *cert; 302 | int code = 0; 303 | 304 | key = k_malloc(2048); 305 | cert = k_malloc(2048); 306 | 307 | memset(key, 0, 2048); 308 | memset(cert, 0, 2048); 309 | 310 | code = degu_coap_request("x509/key", COAP_METHOD_GET, key, NULL); 311 | if (code == COAP_RESPONSE_CODE_NOT_FOUND) { 312 | if (a71ch_has_asset()) { 313 | code = COAP_RESPONSE_CODE_CONTENT; 314 | } 315 | goto end; 316 | } else if (code < COAP_RESPONSE_CODE_OK) { 317 | goto end; 318 | } 319 | 320 | code = degu_coap_request("x509/cert", COAP_METHOD_GET, cert, NULL); 321 | if (code == COAP_RESPONSE_CODE_NOT_FOUND) { 322 | if (a71ch_has_asset()) { 323 | code = COAP_RESPONSE_CODE_CONTENT; 324 | } 325 | goto end; 326 | } else if (code < COAP_RESPONSE_CODE_OK) { 327 | goto end; 328 | } 329 | 330 | if (a71ch_update_asset(key, cert) != 0) { 331 | code = 0; 332 | } 333 | 334 | end: 335 | k_free(key); 336 | k_free(cert); 337 | return code; 338 | } 339 | 340 | int degu_connect(void) 341 | { 342 | return degu_coap_request("con/connection", COAP_METHOD_PUT, "", NULL); 343 | } 344 | 345 | int degu_send_asset(void) 346 | { 347 | char *key; 348 | char *cert; 349 | /* char timeout[4]; */ 350 | int code = 0; 351 | 352 | key = k_malloc(4096); 353 | cert = k_malloc(4096); 354 | 355 | memset(key, 0, 4096); 356 | memset(cert, 0, 4096); 357 | 358 | if (LIBA71CH_open() != 0) { 359 | goto end; 360 | } 361 | 362 | if (LIBA71CH_getKeyAndCert(key, cert) != 0) { 363 | LIBA71CH_finalize(); 364 | goto end; 365 | } 366 | 367 | LIBA71CH_finalize(); 368 | 369 | /* strcpy(timeout, DEGU_TEST_TIMEOUT_SEC); */ 370 | 371 | code = degu_coap_request("con/key", COAP_METHOD_PUT, key, NULL); 372 | if (code < COAP_RESPONSE_CODE_OK) { 373 | goto end; 374 | } 375 | code = degu_coap_request("con/cert", COAP_METHOD_PUT, cert, NULL); 376 | if (code < COAP_RESPONSE_CODE_OK) { 377 | goto end; 378 | } 379 | /* do not send timeout. 380 | If the shadow update interval is longer than this value, 381 | TLS communication between the Degu gateway and AWS is disconnected. 382 | It takes about 4 seconds to reconnect the connection. 383 | In the future, it will be possible to set the timeout value variably. 384 | code = degu_coap_request("con/timeout", COAP_METHOD_PUT, timeout, NULL); 385 | if (code < COAP_RESPONSE_CODE_OK){ 386 | goto end; 387 | } 388 | */ 389 | 390 | end: 391 | k_free(key); 392 | k_free(cert); 393 | return code; 394 | } 395 | 396 | void openthread_join_success_handler(struct k_work *work) 397 | { 398 | struct device *gpio1 = device_get_binding(DT_GPIO_P1_DEV_NAME); 399 | 400 | degu_get_asset(); 401 | 402 | gpio_pin_configure(gpio1, 7, GPIO_DIR_OUT); 403 | gpio_pin_write(gpio1, 7, 0); 404 | } 405 | -------------------------------------------------------------------------------- /degu_ota.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Atmark Techno, Inc. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "mbedtls/md5.h" 36 | #include "degu_utils.h" 37 | #include "zcoap.h" 38 | #include "degu_ota.h" 39 | #include "version.h" 40 | 41 | #define FIRWARE_SIZE_SLOT0 ((uint32_t *)0x0001400CL) 42 | #define BOOT_MAGIC_SZ 16 43 | #define BOOT_MAGIC_OFFS (DT_FLASH_AREA_IMAGE_1_SIZE - BOOT_MAGIC_SZ) 44 | 45 | LOG_MODULE_REGISTER(degu_ota); 46 | 47 | static u32_t boot_img_magic[4] = { 48 | 0xf395c277, 49 | 0x7fefd260, 50 | 0x0f505235, 51 | 0x8079b62c, 52 | }; 53 | 54 | struct device *flash_dev; 55 | struct fs_file_t file; 56 | struct fs_dirent dirent; 57 | 58 | u16_t payload_len; 59 | u8_t *payload; 60 | u32_t byte_written; 61 | 62 | char script_user_ver[33]; 63 | char config_user_ver[33]; 64 | char firmware_system_ver[33]; 65 | char firmware_ver[33]; 66 | 67 | bool update_flag_script_user; 68 | bool update_flag_config_user; 69 | bool update_flag_firmware_system; 70 | 71 | struct shadow_send { 72 | struct state_send { 73 | struct reported { 74 | char *script_user_ver; 75 | char *config_user_ver; 76 | char *firmware_system; 77 | char *firmware_system_ver; 78 | char *firmware_ver; 79 | } reported; 80 | } state; 81 | } shadow_send; 82 | 83 | struct shadow_recv { 84 | struct state_recv { 85 | struct desired { 86 | char *script_user; 87 | char *script_user_ver; 88 | char *config_user; 89 | char *config_user_ver; 90 | char *firmware_system; 91 | char *firmware_system_ver; 92 | } desired; 93 | } state; 94 | } shadow_recv; 95 | 96 | static const struct json_obj_descr reported_descr[] = { 97 | JSON_OBJ_DESCR_PRIM(struct reported, script_user_ver, JSON_TOK_STRING), 98 | JSON_OBJ_DESCR_PRIM(struct reported, config_user_ver, JSON_TOK_STRING), 99 | JSON_OBJ_DESCR_PRIM(struct reported, firmware_system_ver, JSON_TOK_STRING), 100 | JSON_OBJ_DESCR_PRIM(struct reported, firmware_ver, JSON_TOK_STRING), 101 | }; 102 | 103 | static const struct json_obj_descr desired_descr[] = { 104 | JSON_OBJ_DESCR_PRIM(struct desired, script_user, JSON_TOK_STRING), 105 | JSON_OBJ_DESCR_PRIM(struct desired, script_user_ver, JSON_TOK_STRING), 106 | JSON_OBJ_DESCR_PRIM(struct desired, config_user, JSON_TOK_STRING), 107 | JSON_OBJ_DESCR_PRIM(struct desired, config_user_ver, JSON_TOK_STRING), 108 | JSON_OBJ_DESCR_PRIM(struct desired, firmware_system, JSON_TOK_STRING), 109 | JSON_OBJ_DESCR_PRIM(struct desired, firmware_system_ver, JSON_TOK_STRING), 110 | }; 111 | 112 | static const struct json_obj_descr state_send_descr[] = { 113 | JSON_OBJ_DESCR_OBJECT(struct state_send, reported, reported_descr), 114 | }; 115 | 116 | static const struct json_obj_descr state_recv_descr[] = { 117 | JSON_OBJ_DESCR_OBJECT(struct state_recv, desired, desired_descr), 118 | }; 119 | 120 | static const struct json_obj_descr shadow_send_descr[] = { 121 | JSON_OBJ_DESCR_OBJECT(struct shadow_send, state, state_send_descr), 122 | }; 123 | 124 | static const struct json_obj_descr shadow_recv_descr[] = { 125 | JSON_OBJ_DESCR_OBJECT(struct shadow_recv, state, state_recv_descr), 126 | }; 127 | 128 | static char *md5sum(char *buf, int len) 129 | { 130 | unsigned char output[16]; 131 | static char outword[33]; 132 | mbedtls_md5_ret(buf, len, output); 133 | for(int i = 0; i<16; i++){ 134 | sprintf(outword+i*2, "%02x", output[i]); 135 | } 136 | outword[32] = '\0'; 137 | return outword; 138 | } 139 | 140 | static int user_sum(char *path, char *md5) 141 | { 142 | int err, offset = 0; 143 | char *file_data; 144 | int count = INT_MAX; 145 | int read = 0; 146 | 147 | err = fs_stat(path, &dirent); 148 | if(err) { 149 | LOG_ERR("Failed to stat file"); 150 | strcpy(md5, "none"); 151 | return 1; 152 | } 153 | 154 | err = fs_open(&file, path); 155 | if(err) { 156 | LOG_ERR("Can't open file"); 157 | strcpy(md5, "none"); 158 | return 1; 159 | } 160 | 161 | if (offset > 0) { 162 | fs_seek(&file, offset, FS_SEEK_SET); 163 | } 164 | 165 | file_data = k_malloc(dirent.size); 166 | if (!file_data) { 167 | LOG_ERR("Cannot malloc for a user file"); 168 | return 1; 169 | } 170 | 171 | while(1){ 172 | read = fs_read(&file, file_data + offset, MIN(count, sizeof(file_data))); 173 | if (read <= 0) { 174 | break; 175 | } 176 | offset += read; 177 | count -= read; 178 | } 179 | 180 | strcpy(md5, md5sum(file_data, dirent.size)); 181 | LOG_INF("%s : %s\n", path, md5); 182 | 183 | k_free(file_data); 184 | fs_close(&file); 185 | 186 | return 0; 187 | } 188 | 189 | static int firmware_sum(char *md5) 190 | { 191 | int size = *FIRWARE_SIZE_SLOT0 + 848; 192 | 193 | strcpy(md5, md5sum((char *)DT_FLASH_AREA_IMAGE_0_OFFSET, size)); 194 | LOG_INF("firmware size: %d, md5sum: %s", size, md5); 195 | 196 | return 0; 197 | } 198 | 199 | int update_init(void) 200 | { 201 | char shadow_encoded[1024]; 202 | memset(shadow_encoded, 0, 1024); 203 | 204 | degu_get_asset(); 205 | 206 | flash_dev = device_get_binding(DT_FLASH_DEV_NAME); 207 | if (!flash_dev) { 208 | LOG_ERR("failed to device_get_binding()\n"); 209 | return DEGU_OTA_ERR; 210 | } 211 | 212 | payload = (u8_t *)k_malloc(MAX_COAP_MSG_LEN); 213 | if (!payload) { 214 | LOG_ERR("Cannot malloc for payload"); 215 | return DEGU_OTA_ERR; 216 | } 217 | memset(payload, 0, MAX_COAP_MSG_LEN); 218 | 219 | update_flag_script_user = false; 220 | update_flag_config_user = false; 221 | update_flag_firmware_system = false; 222 | 223 | user_sum("/NAND:/main.py", script_user_ver); 224 | shadow_send.state.reported.script_user_ver = script_user_ver; 225 | 226 | user_sum("/NAND:/CONFIG", config_user_ver); 227 | shadow_send.state.reported.config_user_ver = config_user_ver; 228 | 229 | firmware_sum(firmware_system_ver); 230 | shadow_send.state.reported.firmware_system_ver = firmware_system_ver; 231 | 232 | sprintf(firmware_ver, "%s.%s.%s", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION); 233 | shadow_send.state.reported.firmware_ver = firmware_ver; 234 | 235 | json_obj_encode_buf(shadow_send_descr, ARRAY_SIZE(shadow_send_descr), 236 | &shadow_send, shadow_encoded, sizeof(shadow_encoded)); 237 | 238 | return degu_coap_request("thing", COAP_METHOD_POST, shadow_encoded, NULL) < COAP_RESPONSE_CODE_OK ? DEGU_OTA_ERR : DEGU_OTA_OK; 239 | } 240 | 241 | int erase_flash_slot1(void) 242 | { 243 | int err; 244 | 245 | LOG_INF("Erasing slot-1..."); 246 | 247 | flash_write_protection_set(flash_dev, false); 248 | err = flash_erase(flash_dev, DT_FLASH_AREA_IMAGE_1_OFFSET, DT_FLASH_AREA_IMAGE_1_SIZE); 249 | flash_write_protection_set(flash_dev, true); 250 | if (err) { 251 | LOG_INF("Erasing slot-1 failed"); 252 | return 1; 253 | } 254 | 255 | LOG_INF("Erased slot-1 "); 256 | 257 | return 0; 258 | } 259 | 260 | int write_flash_slot1(int written, void *data, int len) 261 | { 262 | int err; 263 | 264 | if (flash_write_protection_set(flash_dev, false)) { 265 | LOG_ERR("err flash_write_protection_set(false).\n"); 266 | return 1; 267 | } 268 | 269 | err = flash_write(flash_dev, DT_FLASH_AREA_IMAGE_1_OFFSET + written, data, len); 270 | 271 | if (flash_write_protection_set(flash_dev, true)) { 272 | LOG_ERR("err flash_write_protection_set(true).\n"); 273 | } 274 | 275 | if (err) { 276 | return 1; 277 | } 278 | /* 279 | * verify 280 | */ 281 | 282 | return 0; 283 | } 284 | 285 | void write_file(u8_t *buf, u16_t len) 286 | { 287 | fs_write(&file, buf, len); 288 | fs_sync(&file); 289 | } 290 | 291 | void write_firmware(u8_t *buf, u16_t len) 292 | { 293 | write_flash_slot1(byte_written, buf, len); 294 | byte_written += len; 295 | LOG_INF("Wrote: %d", byte_written); 296 | } 297 | 298 | void write_img_magic() { 299 | write_flash_slot1(BOOT_MAGIC_OFFS, boot_img_magic, BOOT_MAGIC_SZ); 300 | } 301 | 302 | int do_update(void) 303 | { 304 | char request_url[1024]; 305 | int err; 306 | 307 | memset(request_url, 0, 1024); 308 | 309 | json_obj_encode_buf(desired_descr, ARRAY_SIZE(desired_descr), 310 | &shadow_recv.state.desired, request_url, sizeof(request_url)); 311 | 312 | if (update_flag_script_user) { 313 | if (degu_coap_request("update/script_user", COAP_METHOD_PUT, "", NULL) < COAP_RESPONSE_CODE_OK) { 314 | goto error; 315 | } 316 | 317 | if (degu_coap_request("update/script_user", COAP_METHOD_POST, request_url, NULL) < COAP_RESPONSE_CODE_OK) { 318 | goto error; 319 | } 320 | 321 | err = fs_stat("/NAND:/main.py", &dirent); 322 | if (!err) { 323 | fs_unlink("/NAND:/main.py"); 324 | } 325 | 326 | err = fs_open(&file, "/NAND:/main.py"); 327 | if(err) { 328 | LOG_ERR("Can't open user script"); 329 | goto error; 330 | } 331 | 332 | memset(payload, 0, 1024); 333 | if (degu_coap_request("update/script_user", COAP_METHOD_GET, payload, &write_file) < COAP_RESPONSE_CODE_OK) { 334 | fs_close(&file); 335 | goto error; 336 | } 337 | 338 | fs_close(&file); 339 | } 340 | 341 | if (update_flag_config_user) { 342 | if (degu_coap_request("update/config_user", COAP_METHOD_PUT, "", NULL) < COAP_RESPONSE_CODE_OK) { 343 | goto error; 344 | } 345 | 346 | if (degu_coap_request("update/config_user", COAP_METHOD_POST, request_url, NULL) < COAP_RESPONSE_CODE_OK) { 347 | goto error; 348 | } 349 | 350 | err = fs_stat("/NAND:/CONFIG", &dirent); 351 | if (!err) { 352 | fs_unlink("/NAND:/CONFIG"); 353 | } 354 | 355 | err = fs_open(&file, "/NAND:/CONFIG"); 356 | if(err) { 357 | LOG_ERR("Can't open config file"); 358 | goto error; 359 | } 360 | 361 | memset(payload, 0, 1024); 362 | if (degu_coap_request("update/config_user", COAP_METHOD_GET, payload, &write_file) < COAP_RESPONSE_CODE_OK) { 363 | fs_close(&file); 364 | goto error; 365 | } 366 | 367 | fs_close(&file); 368 | } 369 | 370 | if (update_flag_firmware_system) { 371 | byte_written = 0; 372 | 373 | if (degu_coap_request("update/firmware_system", COAP_METHOD_PUT, "", NULL) < COAP_RESPONSE_CODE_OK) { 374 | goto error; 375 | } 376 | 377 | if (degu_coap_request("update/firmware_system", COAP_METHOD_POST, request_url, NULL) < COAP_RESPONSE_CODE_OK) { 378 | goto error; 379 | } 380 | 381 | erase_flash_slot1(); 382 | 383 | memset(payload, 0, 1024); 384 | if (degu_coap_request("update/firmware_system", COAP_METHOD_GET, payload, &write_firmware) < COAP_RESPONSE_CODE_OK) { 385 | goto error; 386 | } 387 | 388 | write_img_magic(); 389 | } 390 | 391 | return DEGU_OTA_OK; 392 | 393 | error: 394 | return DEGU_OTA_ERR; 395 | } 396 | 397 | int check_update(void) 398 | { 399 | int diff; 400 | int ret = DEGU_OTA_ERR; 401 | 402 | if (degu_coap_request("update/status", COAP_METHOD_PUT, "", NULL) < COAP_RESPONSE_CODE_OK) { 403 | goto end; 404 | } 405 | 406 | memset(payload, 0, 1024); 407 | if (degu_coap_request("update/status", COAP_METHOD_GET, payload, NULL) < COAP_RESPONSE_CODE_OK) { 408 | goto end; 409 | } 410 | 411 | if (!payload) { 412 | goto end; 413 | } 414 | 415 | json_obj_parse(payload, strlen(payload), shadow_recv_descr, 416 | ARRAY_SIZE(shadow_recv_descr), &shadow_recv); 417 | 418 | if (shadow_recv.state.desired.script_user_ver != NULL) { 419 | diff = strcmp(shadow_recv.state.desired.script_user_ver, 420 | shadow_send.state.reported.script_user_ver); 421 | if (diff) { 422 | update_flag_script_user = true; 423 | ret = DEGU_OTA_OK; 424 | } 425 | } 426 | if (shadow_recv.state.desired.config_user_ver != NULL) { 427 | diff = strcmp(shadow_recv.state.desired.config_user_ver, 428 | shadow_send.state.reported.config_user_ver); 429 | if (diff) { 430 | update_flag_config_user = true; 431 | ret = DEGU_OTA_OK; 432 | } 433 | } 434 | if (shadow_recv.state.desired.firmware_system_ver != NULL) { 435 | diff = strcmp(shadow_recv.state.desired.firmware_system_ver, 436 | shadow_send.state.reported.firmware_system_ver); 437 | if (diff) { 438 | update_flag_firmware_system = true; 439 | ret = DEGU_OTA_OK; 440 | } 441 | } 442 | 443 | end: 444 | return ret; 445 | } 446 | -------------------------------------------------------------------------------- /modusocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the MicroPython project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2017 Linaro Limited 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "py/mpconfig.h" 28 | #ifdef MICROPY_PY_USOCKET 29 | 30 | #include "py/runtime.h" 31 | #include "py/stream.h" 32 | 33 | #include 34 | #include 35 | // Zephyr's generated version header 36 | #include 37 | #include 38 | #include 39 | #include 40 | #ifdef CONFIG_NET_SOCKETS 41 | #include 42 | #endif 43 | 44 | #define DEBUG_PRINT 0 45 | #if DEBUG_PRINT // print debugging info 46 | #define DEBUG_printf printf 47 | #else // don't print debugging info 48 | #define DEBUG_printf(...) (void)0 49 | #endif 50 | 51 | typedef struct _socket_obj_t { 52 | mp_obj_base_t base; 53 | int ctx; 54 | 55 | #define STATE_NEW 0 56 | #define STATE_CONNECTING 1 57 | #define STATE_CONNECTED 2 58 | #define STATE_PEER_CLOSED 3 59 | int8_t state; 60 | } socket_obj_t; 61 | 62 | STATIC const mp_obj_type_t socket_type; 63 | 64 | // Helper functions 65 | 66 | #define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } 67 | #define RAISE_SOCK_ERRNO(x) { if ((int)(x) == -1) mp_raise_OSError(errno); } 68 | 69 | STATIC void socket_check_closed(socket_obj_t *socket) { 70 | if (socket->ctx == -1) { 71 | // already closed 72 | mp_raise_OSError(EBADF); 73 | } 74 | } 75 | 76 | STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct sockaddr *sockaddr) { 77 | // We employ the fact that port and address offsets are the same for IPv4 & IPv6 78 | struct sockaddr_in *sockaddr_in = (struct sockaddr_in*)sockaddr; 79 | 80 | mp_obj_t *addr_items; 81 | mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); 82 | sockaddr_in->sin_family = net_context_get_family((void*)socket->ctx); 83 | RAISE_ERRNO(net_addr_pton(sockaddr_in->sin_family, mp_obj_str_get_str(addr_items[0]), &sockaddr_in->sin_addr)); 84 | sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1])); 85 | } 86 | 87 | STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { 88 | // We employ the fact that port and address offsets are the same for IPv4 & IPv6 89 | struct sockaddr_in6 *sockaddr_in6 = (struct sockaddr_in6*)addr; 90 | char buf[40]; 91 | net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); 92 | mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); 93 | 94 | tuple->items[0] = mp_obj_new_str(buf, strlen(buf)); 95 | // We employ the fact that port offset is the same for IPv4 & IPv6 96 | // not filled in 97 | //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); 98 | tuple->items[1] = port; 99 | 100 | if (addr->sa_family == AF_INET6) { 101 | tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); // flow_info 102 | tuple->items[3] = MP_OBJ_NEW_SMALL_INT(sockaddr_in6->sin6_scope_id); 103 | } 104 | 105 | return MP_OBJ_FROM_PTR(tuple); 106 | } 107 | 108 | socket_obj_t *socket_new(void) { 109 | socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t); 110 | socket->base.type = (mp_obj_t)&socket_type; 111 | socket->state = STATE_NEW; 112 | return socket; 113 | } 114 | 115 | // Methods 116 | 117 | STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { 118 | socket_obj_t *self = self_in; 119 | if (self->ctx == -1) { 120 | mp_printf(print, ""); 121 | } else { 122 | struct net_context *ctx = (void*)self->ctx; 123 | mp_printf(print, "", ctx, net_context_get_type(ctx)); 124 | } 125 | } 126 | 127 | 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) { 128 | mp_arg_check_num(n_args, n_kw, 0, 4, false); 129 | 130 | socket_obj_t *socket = socket_new(); 131 | 132 | int family = AF_INET; 133 | int socktype = SOCK_STREAM; 134 | int proto = -1; 135 | 136 | if (n_args >= 1) { 137 | family = mp_obj_get_int(args[0]); 138 | if (n_args >= 2) { 139 | socktype = mp_obj_get_int(args[1]); 140 | if (n_args >= 3) { 141 | proto = mp_obj_get_int(args[2]); 142 | } 143 | } 144 | } 145 | 146 | if (proto == -1) { 147 | proto = IPPROTO_TCP; 148 | if (socktype != SOCK_STREAM) { 149 | proto = IPPROTO_UDP; 150 | } 151 | } 152 | 153 | socket->ctx = zsock_socket(family, socktype, proto); 154 | RAISE_SOCK_ERRNO(socket->ctx); 155 | 156 | return MP_OBJ_FROM_PTR(socket); 157 | } 158 | 159 | STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { 160 | socket_obj_t *socket = self_in; 161 | socket_check_closed(socket); 162 | 163 | struct sockaddr sockaddr; 164 | parse_inet_addr(socket, addr_in, &sockaddr); 165 | 166 | int res = zsock_bind(socket->ctx, &sockaddr, sizeof(sockaddr)); 167 | RAISE_SOCK_ERRNO(res); 168 | 169 | return mp_const_none; 170 | } 171 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); 172 | 173 | STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { 174 | socket_obj_t *socket = self_in; 175 | socket_check_closed(socket); 176 | 177 | struct sockaddr sockaddr; 178 | parse_inet_addr(socket, addr_in, &sockaddr); 179 | 180 | int res = zsock_connect(socket->ctx, &sockaddr, sizeof(sockaddr)); 181 | RAISE_SOCK_ERRNO(res); 182 | 183 | return mp_const_none; 184 | } 185 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); 186 | 187 | STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { 188 | socket_obj_t *socket = self_in; 189 | socket_check_closed(socket); 190 | 191 | mp_int_t backlog = mp_obj_get_int(backlog_in); 192 | int res = zsock_listen(socket->ctx, backlog); 193 | RAISE_SOCK_ERRNO(res); 194 | 195 | return mp_const_none; 196 | } 197 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); 198 | 199 | STATIC mp_obj_t socket_accept(mp_obj_t self_in) { 200 | socket_obj_t *socket = self_in; 201 | socket_check_closed(socket); 202 | 203 | struct sockaddr sockaddr; 204 | socklen_t addrlen = sizeof(sockaddr); 205 | int ctx = zsock_accept(socket->ctx, &sockaddr, &addrlen); 206 | 207 | socket_obj_t *socket2 = socket_new(); 208 | socket2->ctx = ctx; 209 | 210 | mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); 211 | client->items[0] = MP_OBJ_FROM_PTR(socket2); 212 | // TODO 213 | client->items[1] = mp_const_none; 214 | 215 | return MP_OBJ_FROM_PTR(client); 216 | } 217 | STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); 218 | 219 | STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { 220 | socket_obj_t *socket = self_in; 221 | if (socket->ctx == -1) { 222 | // already closed 223 | *errcode = EBADF; 224 | return MP_STREAM_ERROR; 225 | } 226 | 227 | ssize_t len = zsock_send(socket->ctx, buf, size, 0); 228 | if (len == -1) { 229 | *errcode = errno; 230 | return MP_STREAM_ERROR; 231 | } 232 | 233 | return len; 234 | } 235 | 236 | STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { 237 | mp_buffer_info_t bufinfo; 238 | mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); 239 | int err = 0; 240 | mp_uint_t len = sock_write(self_in, bufinfo.buf, bufinfo.len, &err); 241 | if (len == MP_STREAM_ERROR) { 242 | mp_raise_OSError(err); 243 | } 244 | return mp_obj_new_int_from_uint(len); 245 | } 246 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); 247 | 248 | STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *errcode) { 249 | socket_obj_t *socket = self_in; 250 | if (socket->ctx == -1) { 251 | // already closed 252 | *errcode = EBADF; 253 | return MP_STREAM_ERROR; 254 | } 255 | 256 | ssize_t recv_len = zsock_recv(socket->ctx, buf, max_len, ZSOCK_MSG_DONTWAIT); 257 | if (recv_len == -1) { 258 | *errcode = errno; 259 | return MP_STREAM_ERROR; 260 | } 261 | 262 | return recv_len; 263 | } 264 | 265 | STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { 266 | mp_int_t max_len = mp_obj_get_int(len_in); 267 | vstr_t vstr; 268 | // +1 to accommodate for trailing \0 269 | vstr_init_len(&vstr, max_len + 1); 270 | 271 | int err; 272 | mp_uint_t len = sock_read(self_in, vstr.buf, max_len, &err); 273 | 274 | if (len == MP_STREAM_ERROR) { 275 | vstr_clear(&vstr); 276 | mp_raise_OSError(err); 277 | } 278 | 279 | if (len == 0) { 280 | vstr_clear(&vstr); 281 | return mp_const_empty_bytes; 282 | } 283 | 284 | vstr.len = len; 285 | return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); 286 | } 287 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); 288 | 289 | STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { 290 | (void)n_args; // always 4 291 | mp_warning("setsockopt() not implemented"); 292 | return mp_const_none; 293 | } 294 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); 295 | 296 | STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { 297 | (void)n_args; 298 | return args[0]; 299 | } 300 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); 301 | 302 | STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { 303 | socket_obj_t *socket = o_in; 304 | (void)arg; 305 | switch (request) { 306 | case MP_STREAM_CLOSE: 307 | if (socket->ctx != -1) { 308 | int res = zsock_close(socket->ctx); 309 | RAISE_SOCK_ERRNO(res); 310 | if (res == -1) { 311 | *errcode = errno; 312 | return MP_STREAM_ERROR; 313 | } 314 | socket->ctx = -1; 315 | } 316 | return 0; 317 | 318 | default: 319 | *errcode = MP_EINVAL; 320 | return MP_STREAM_ERROR; 321 | } 322 | } 323 | 324 | STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { 325 | { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, 326 | { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, 327 | { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, 328 | { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, 329 | { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, 330 | { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, 331 | { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, 332 | { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, 333 | { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, 334 | 335 | { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, 336 | { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, 337 | { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, 338 | { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, 339 | { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, 340 | }; 341 | STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); 342 | 343 | STATIC const mp_stream_p_t socket_stream_p = { 344 | .read = sock_read, 345 | .write = sock_write, 346 | .ioctl = sock_ioctl, 347 | }; 348 | 349 | STATIC const mp_obj_type_t socket_type = { 350 | { &mp_type_type }, 351 | .name = MP_QSTR_socket, 352 | .print = socket_print, 353 | .make_new = socket_make_new, 354 | .protocol = &socket_stream_p, 355 | .locals_dict = (mp_obj_t)&socket_locals_dict, 356 | }; 357 | 358 | // 359 | // getaddrinfo() implementation 360 | // 361 | 362 | typedef struct _getaddrinfo_state_t { 363 | mp_obj_t result; 364 | struct k_sem sem; 365 | mp_obj_t port; 366 | int status; 367 | } getaddrinfo_state_t; 368 | 369 | void dns_resolve_cb(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { 370 | getaddrinfo_state_t *state = user_data; 371 | DEBUG_printf("dns status: %d\n", status); 372 | 373 | if (info == NULL) { 374 | if (status == DNS_EAI_ALLDONE) { 375 | status = 0; 376 | } 377 | state->status = status; 378 | k_sem_give(&state->sem); 379 | return; 380 | } 381 | 382 | mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); 383 | tuple->items[0] = MP_OBJ_NEW_SMALL_INT(info->ai_family); 384 | // info->ai_socktype not filled 385 | tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM); 386 | // info->ai_protocol not filled 387 | tuple->items[2] = MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP); 388 | tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); 389 | tuple->items[4] = format_inet_addr(&info->ai_addr, state->port); 390 | mp_obj_list_append(state->result, MP_OBJ_FROM_PTR(tuple)); 391 | } 392 | 393 | STATIC mp_obj_t mod_getaddrinfo(size_t n_args, const mp_obj_t *args) { 394 | mp_obj_t host_in = args[0], port_in = args[1]; 395 | const char *host = mp_obj_str_get_str(host_in); 396 | mp_int_t family = 0; 397 | if (n_args > 2) { 398 | family = mp_obj_get_int(args[2]); 399 | } 400 | 401 | getaddrinfo_state_t state; 402 | // Just validate that it's int 403 | (void)mp_obj_get_int(port_in); 404 | state.port = port_in; 405 | state.result = mp_obj_new_list(0, NULL); 406 | k_sem_init(&state.sem, 0, UINT_MAX); 407 | 408 | for (int i = 2; i--;) { 409 | int type = (family != AF_INET6 ? DNS_QUERY_TYPE_A : DNS_QUERY_TYPE_AAAA); 410 | RAISE_ERRNO(dns_get_addr_info(host, type, NULL, dns_resolve_cb, &state, 3000)); 411 | k_sem_take(&state.sem, K_FOREVER); 412 | if (family != 0) { 413 | break; 414 | } 415 | family = AF_INET6; 416 | } 417 | 418 | // Raise error only if there's nothing to return, otherwise 419 | // it may be IPv4 vs IPv6 differences. 420 | mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(state.result)); 421 | if (state.status != 0 && len == 0) { 422 | mp_raise_OSError(state.status); 423 | } 424 | 425 | return state.result; 426 | } 427 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_getaddrinfo_obj, 2, 3, mod_getaddrinfo); 428 | 429 | 430 | STATIC mp_obj_t pkt_get_info(void) { 431 | struct k_mem_slab *rx, *tx; 432 | struct net_buf_pool *rx_data, *tx_data; 433 | net_pkt_get_info(&rx, &tx, &rx_data, &tx_data); 434 | mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); 435 | t->items[0] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(rx)); 436 | t->items[1] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(tx)); 437 | t->items[2] = MP_OBJ_NEW_SMALL_INT(rx_data->avail_count); 438 | t->items[3] = MP_OBJ_NEW_SMALL_INT(tx_data->avail_count); 439 | return MP_OBJ_FROM_PTR(t); 440 | } 441 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(pkt_get_info_obj, pkt_get_info); 442 | 443 | STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { 444 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, 445 | // objects 446 | { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, 447 | // class constants 448 | { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, 449 | { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, 450 | 451 | { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, 452 | { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, 453 | 454 | { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, 455 | { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(2) }, 456 | 457 | { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_getaddrinfo_obj) }, 458 | { MP_ROM_QSTR(MP_QSTR_pkt_get_info), MP_ROM_PTR(&pkt_get_info_obj) }, 459 | }; 460 | 461 | STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); 462 | 463 | const mp_obj_module_t mp_module_usocket = { 464 | .base = { &mp_type_module }, 465 | .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, 466 | }; 467 | 468 | #endif // MICROPY_PY_USOCKET 469 | --------------------------------------------------------------------------------