diff --git a/.travis.yml b/.travis.yml index 205c3cef12a99..c598783f44039 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ before_script: - sudo apt-get install -y python3.4 python3 gcc-4.7 gcc-multilib gcc-arm-none-eabi qemu-system mingw32 # For teensy build - sudo apt-get install realpath + # For coverage testing + - sudo pip install cpp-coveralls script: - make -C minimal test @@ -25,8 +27,17 @@ script: - make -C cc3200 BTARGET=bootloader BTYPE=release - make -C windows CROSS_COMPILE=i586-mingw32msvc- - - (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests) - - (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native) + # run tests without coverage info + #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests) + #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native) + + # run tests with coverage info + - make -C unix CC=gcc-4.7 coverage + - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --emit native) + +after_success: + - (cd unix && coveralls --root .. --build-root . --gcov $(which gcov-4.7) --gcov-options '\-o build-coverage/' --include py --include extmod) after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) diff --git a/README.md b/README.md index 1eec212575a15..2cf26a2f3ef1f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -[![Build Status][travis-img]][travis-repo] +[![Build Status][travis-img]][travis-repo] [![Coverage Status][coveralls-img]][coveralls-repo] [travis-img]: https://travis-ci.org/micropython/micropython.png?branch=master [travis-repo]: https://travis-ci.org/micropython/micropython +[coveralls-img]: https://coveralls.io/repos/micropython/micropython/badge.png?branch=master +[coveralls-repo]: https://coveralls.io/r/micropython/micropython?branch=master The Micro Python project ======================== diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 8f417f735b2e2..8075cf7b833b7 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -126,13 +126,18 @@ Methods Return value: buffer of data bytes. -.. method:: can.send(send, addr, \*, timeout=5000) +.. method:: can.send(send, addr, \*, timeout=0) Send a message on the bus: - ``send`` is the data to send (an integer to send, or a buffer object). - ``addr`` is the address to send to - ``timeout`` is the timeout in milliseconds to wait for the send. + If timeout is 0 the message is placed in a buffer in one of three hardware + buffers and the method returns immediately. If all three buffers are in use + an exception is thrown. If timeout is not 0, the method waits until the + message is transmitted. If the message can't be transmitted within the + specified time an exception is thrown. Return value: ``None``. diff --git a/drivers/onewire/ds18x20.py b/drivers/onewire/ds18x20.py new file mode 100644 index 0000000000000..06c9fc968b3ab --- /dev/null +++ b/drivers/onewire/ds18x20.py @@ -0,0 +1,104 @@ +""" +DS18x20 temperature sensor driver for MicroPython. + +This driver uses the OneWire driver to control DS18S20 and DS18B20 +temperature sensors. It supports multiple devices on the same 1-wire bus. + +The following example assumes the ground of your DS18x20 is connected to +Y11, vcc is connected to Y9 and the data pin is connected to Y10. + +>>> gnd = Pin('Y11') +>>> gnd.init(Pin.OUT_PP) +>>> gnd.low() + +>>> vcc = Pin('Y9') +>>> vcc.init(Pin.OUT_PP) +>>> vcc.high() + +>>> d = DS18X20(Pin('Y10')) + +Call read_temps to read all sensors: + +>>> result = d.read_temps() +>>> print(result) +[20.875, 20.8125] + +Call read_temp to read the temperature of a specific sensor: + +>>> result = d.read_temp(d.roms[0]) +>>> print(result) +20.25 + +If only one DS18x20 is attached to the bus, then you don't need to +pass a ROM to read_temp: + +>>> result = d.read_temp() +>>> print(result) +20.25 + +""" + +from onewire import OneWire + +class DS18X20(object): + def __init__(self, pin): + self.ow = OneWire(pin) + # Scan the 1-wire devices, but only keep those which have the + # correct # first byte in their rom for a DS18x20 device. + self.roms = [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] + + def _select_rom(self, rom): + if rom: + self.ow.select_rom(rom) + else: + self.ow.skip_rom() + + def read_temp(self, rom=None): + """ + Read and return the temperature of one DS18x20 device. + Pass the 8-byte bytes object with the ROM of the specific device you want to read. + If only one DS18x20 device is attached to the bus you may omit the rom parameter. + """ + ow = self.ow + ow.reset() + self._select_rom(rom) + ow.write_byte(0x44) # Convert Temp + while True: + if ow.read_bit(): + break + ow.reset() + self._select_rom(rom) + ow.write_byte(0xbe) # Read scratch + data = ow.read_bytes(9) + return self.convert_temp(rom[0], data) + + def read_temps(self): + """ + Read and return the temperatures of all attached DS18x20 devices. + """ + temps = [] + for rom in self.roms: + temps.append(self.read_temp(rom)) + return temps + + def convert_temp(self, rom0, data): + """ + Convert the raw temperature data into degrees celsius and return as a float. + """ + temp_lsb = data[0] + temp_msb = data[1] + if rom0 == 0x10: + if temp_msb != 0: + # convert negative number + temp_read = temp_lsb >> 1 | 0x80 # truncate bit 0 by shifting, fill high bit with 1. + temp_read = -((~temp_read + 1) & 0xff) # now convert from two's complement + else: + temp_read = temp_lsb >> 1 # truncate bit 0 by shifting + count_remain = data[6] + count_per_c = data[7] + temp = temp_read - 0.25 + (count_per_c - count_remain) / count_per_c + return temp + elif rom0 == 0x28: + return (temp_msb << 8 | temp_lsb) / 16 + else: + assert False diff --git a/drivers/onewire/onewire.py b/drivers/onewire/onewire.py new file mode 100644 index 0000000000000..ffeb130d6e2d9 --- /dev/null +++ b/drivers/onewire/onewire.py @@ -0,0 +1,336 @@ +""" +OneWire library ported to MicroPython by Jason Hildebrand. + + +TODO: + * implement and test parasite-power mode (as an init option) + * port the crc checks + +The original upstream copyright and terms follow. +------------------------------------------------------------------------------ + +Copyright (c) 2007, Jim Studt (original old version - many contributors since) + +OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since +January 2010. + +26 Sept 2008 -- Robin James + +Jim Studt's original library was modified by Josh Larios. + +Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. +""" + +import pyb +from pyb import disable_irq +from pyb import enable_irq + +class OneWire: + def __init__(self, pin): + """ + Pass the data pin connected to your one-wire device(s), for example Pin('X1'). + The one-wire protocol allows for multiple devices to be attached. + """ + self.data_pin = pin + self.write_delays = (1, 40, 40, 1) + self.read_delays = (1, 1, 40) + + # cache a bunch of methods and attributes. This is necessary in _write_bit and + # _read_bit to achieve the timing required by the OneWire protocol. + self.cache = (pin.init, pin.value, pin.OUT_PP, pin.IN, pin.PULL_NONE) + + pin.init(pin.IN, pin.PULL_UP) + + def reset(self): + """ + Perform the onewire reset function. + Returns 1 if a device asserted a presence pulse, 0 otherwise. + + If you receive 0, then check your wiring and make sure you are providing + power and ground to your devices. + """ + retries = 25 + self.data_pin.init(self.data_pin.IN, self.data_pin.PULL_UP) + + # We will wait up to 250uS for + # the bus to come high, if it doesn't then it is broken or shorted + # and we return a 0; + + # wait until the wire is high... just in case + while True: + if self.data_pin.value(): + break + retries -= 1 + if retries == 0: + raise OSError("OneWire pin didn't go high") + pyb.udelay(10) + + # pull the bus low for at least 480us + self.data_pin.low() + self.data_pin.init(self.data_pin.OUT_PP) + pyb.udelay(480) + + # If there is a slave present, it should pull the bus low within 60us + i = pyb.disable_irq() + self.data_pin.init(self.data_pin.IN, self.data_pin.PULL_UP) + pyb.udelay(70) + presence = not self.data_pin.value() + pyb.enable_irq(i) + pyb.udelay(410) + return presence + + def write_bit(self, value): + """ + Write a single bit. + """ + pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP = self.cache + self._write_bit(value, pin_init, pin_value, Pin_OUT_PP) + + def _write_bit(self, value, pin_init, pin_value, Pin_OUT_PP): + """ + Write a single bit - requires cached methods/attributes be passed as arguments. + See also write_bit() + """ + d0, d1, d2, d3 = self.write_delays + udelay = pyb.udelay + if value: + # write 1 + i = disable_irq() + pin_value(0) + pin_init(Pin_OUT_PP) + udelay(d0) + pin_value(1) + enable_irq(i) + udelay(d1) + else: + # write 0 + i = disable_irq() + pin_value(0) + pin_init(Pin_OUT_PP) + udelay(d2) + pin_value(1) + enable_irq(i) + udelay(d3) + + def write_byte(self, value): + """ + Write a byte. The pin will go tri-state at the end of the write to avoid + heating in a short or other mishap. + """ + pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP = self.cache + for i in range(8): + self._write_bit(value & 1, pin_init, pin_value, Pin_OUT_PP) + value >>= 1 + pin_init(Pin_IN, Pin_PULL_UP) + + def write_bytes(self, bytestring): + """ + Write a sequence of bytes. + """ + for byte in bytestring: + self.write_byte(byte) + + def _read_bit(self, pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP): + """ + Read a single bit - requires cached methods/attributes be passed as arguments. + See also read_bit() + """ + d0, d1, d2 = self.read_delays + udelay = pyb.udelay + pin_init(Pin_IN, Pin_PULL_UP) # TODO why do we need this? + i = disable_irq() + pin_value(0) + pin_init(Pin_OUT_PP) + udelay(d0) + pin_init(Pin_IN, Pin_PULL_UP) + udelay(d1) + value = pin_value() + enable_irq(i) + udelay(d2) + return value + + def read_bit(self): + """ + Read a single bit. + """ + pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP = self.cache + return self._read_bit(pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP) + + def read_byte(self): + """ + Read a single byte and return the value as an integer. + See also read_bytes() + """ + pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP = self.cache + value = 0 + for i in range(8): + bit = self._read_bit(pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP) + value |= bit << i + return value + + def read_bytes(self, count): + """ + Read a sequence of N bytes. + The bytes are returned as a bytearray. + """ + s = bytearray(count) + for i in range(count): + s[i] = self.read_byte() + return s + + def select_rom(self, rom): + """ + Select a specific device to talk to. Pass in rom as a bytearray (8 bytes). + """ + assert len(rom) == 8, "ROM must be 8 bytes" + self.reset() + self.write_byte(0x55) # ROM MATCH + self.write_bytes(rom) + + def read_rom(self): + """ + Read the ROM - this works if there is only a single device attached. + """ + self.reset() + self.write_byte(0x33) # READ ROM + rom = self.read_bytes(8) + # TODO: check CRC of the ROM + return rom + + def skip_rom(self): + """ + Send skip-rom command - this works if there is only one device attached. + """ + self.write_byte(0xCC) # SKIP ROM + + def depower(self): + self.data_pin.init(self.data_pin.IN, self.data_pin.PULL_NONE) + + def scan(self): + """ + Return a list of ROMs for all attached devices. + Each ROM is returned as a bytes object of 8 bytes. + """ + devices = [] + self._reset_search() + while True: + rom = self._search() + if not rom: + return devices + devices.append(rom) + + def _reset_search(self): + self.last_discrepancy = 0 + self.last_device_flag = False + self.last_family_discrepancy = 0 + self.rom = bytearray(8) + + def _search(self): + # initialize for search + id_bit_number = 1 + last_zero = 0 + rom_byte_number = 0 + rom_byte_mask = 1 + search_result = 0 + pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP = self.cache + + # if the last call was not the last one + if not self.last_device_flag: + # 1-Wire reset + if not self.reset(): + self._reset_search() + return None + + # issue the search command + self.write_byte(0xF0) + + # loop to do the search + while rom_byte_number < 8: # loop until through all ROM bytes 0-7 + # read a bit and its complement + id_bit = self._read_bit(pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP) + cmp_id_bit = self._read_bit(pin_init, pin_value, Pin_OUT_PP, Pin_IN, Pin_PULL_UP) + + # check for no devices on 1-wire + if (id_bit == 1) and (cmp_id_bit == 1): + break + else: + # all devices coupled have 0 or 1 + if (id_bit != cmp_id_bit): + search_direction = id_bit # bit write value for search + else: + # if this discrepancy if before the Last Discrepancy + # on a previous next then pick the same as last time + if (id_bit_number < self.last_discrepancy): + search_direction = (self.rom[rom_byte_number] & rom_byte_mask) > 0 + else: + # if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == self.last_discrepancy) + + # if 0 was picked then record its position in LastZero + if search_direction == 0: + last_zero = id_bit_number + + # check for Last discrepancy in family + if last_zero < 9: + self.last_family_discrepancy = last_zero + + # set or clear the bit in the ROM byte rom_byte_number + # with mask rom_byte_mask + if search_direction == 1: + self.rom[rom_byte_number] |= rom_byte_mask + else: + self.rom[rom_byte_number] &= ~rom_byte_mask + + # serial number search direction write bit + #print('sd', search_direction) + self.write_bit(search_direction) + + # increment the byte counter id_bit_number + # and shift the mask rom_byte_mask + id_bit_number += 1 + rom_byte_mask <<= 1 + + # if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if rom_byte_mask == 0x100: + rom_byte_number += 1 + rom_byte_mask = 1 + + # if the search was successful then + if not (id_bit_number < 65): + # search successful so set last_discrepancy,last_device_flag,search_result + self.last_discrepancy = last_zero + + # check for last device + if self.last_discrepancy == 0: + self.last_device_flag = True + search_result = True + + # if no device found then reset counters so next 'search' will be like a first + if not search_result or not self.rom[0]: + self._reset_search() + return None + else: + return bytes(self.rom) diff --git a/py/asmthumb.c b/py/asmthumb.c index d5452ff6f5358..5bf2d80bb4073 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -297,25 +297,26 @@ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction - if (SIGNED_FIT12(rel)) { - asm_thumb_op16(as, OP_B_N(rel)); - return true; - } else { - return false; - } + asm_thumb_op16(as, OP_B_N(rel)); + return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT12(rel); } #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) -bool asm_thumb_bcc_n_label(asm_thumb_t *as, int cond, uint label) { +// all these bit arithmetics need coverage testing! +#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) +#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) + +bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction - if (SIGNED_FIT9(rel)) { + if (!wide) { asm_thumb_op16(as, OP_BCC_N(cond, rel)); - return true; + return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT9(rel); } else { - return false; + asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); + return true; } } @@ -326,12 +327,8 @@ bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction - if (SIGNED_FIT23(rel)) { - asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); - return true; - } else { - return false; - } + asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); + return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT23(rel); } void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { @@ -416,10 +413,6 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) { } } -// all these bit arithmetics need coverage testing! -#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) -#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) - void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->code_offset; diff --git a/py/asmthumb.h b/py/asmthumb.h index 2dd4dbb995cb4..1ce91d38d6057 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -216,7 +216,7 @@ void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_ // these return true if the destination is in range, false otherwise bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); -bool asm_thumb_bcc_n_label(asm_thumb_t *as, int cond, uint label); +bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide); bool asm_thumb_bl_label(asm_thumb_t *as, uint label); void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience diff --git a/py/compile.c b/py/compile.c index 41e2610c04312..d688bf4022ad9 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3389,7 +3389,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_expr_stmt) { // not an instruction; error not_an_instruction: - compile_syntax_error(comp, nodes[i], "inline assembler expecting an instruction"); + compile_syntax_error(comp, nodes[i], "expecting an assembler instruction"); return; } @@ -3420,16 +3420,19 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind // emit instructions if (op == MP_QSTR_label) { if (!(n_args == 1 && MP_PARSE_NODE_IS_ID(pn_arg[0]))) { - compile_syntax_error(comp, nodes[i], "inline assembler 'label' requires 1 argument"); + compile_syntax_error(comp, nodes[i], "'label' requires 1 argument"); return; } uint lab = comp_next_label(comp); if (pass > MP_PASS_SCOPE) { - EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0])); + if (!EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]))) { + compile_syntax_error(comp, nodes[i], "label redefined"); + return; + } } } else if (op == MP_QSTR_align) { if (!(n_args == 1 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { - compile_syntax_error(comp, nodes[i], "inline assembler 'align' requires 1 argument"); + compile_syntax_error(comp, nodes[i], "'align' requires 1 argument"); return; } if (pass > MP_PASS_SCOPE) { @@ -3437,14 +3440,14 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } } else if (op == MP_QSTR_data) { if (!(n_args >= 2 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { - compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires at least 2 arguments"); + compile_syntax_error(comp, nodes[i], "'data' requires at least 2 arguments"); return; } if (pass > MP_PASS_SCOPE) { mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]); for (uint j = 1; j < n_args; j++) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) { - compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments"); + compile_syntax_error(comp, nodes[i], "'data' requires integer arguments"); return; } EMIT_INLINE_ASM_ARG(data, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j])); @@ -3605,15 +3608,16 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is comp->is_repl = is_repl; comp->compile_error = MP_OBJ_NULL; - // optimise constants + // create the module scope + scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, pn, emit_opt); + + // optimise constants (scope must be set for error messages to work) + comp->scope_cur = module_scope; mp_map_t consts; mp_map_init(&consts, 0); - pn = fold_constants(comp, pn, &consts); + module_scope->pn = fold_constants(comp, module_scope->pn, &consts); mp_map_deinit(&consts); - // set the outer scope - scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, pn, emit_opt); - // compile pass 1 comp->emit = emit_pass1_new(); comp->emit_method_table = &emit_pass1_method_table; @@ -3764,7 +3768,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is #endif // !MICROPY_EMIT_CPYTHON // free the parse tree - mp_parse_node_free(pn); + mp_parse_node_free(module_scope->pn); // free the scopes mp_raw_code_t *outer_raw_code = module_scope->raw_code; diff --git a/py/emit.h b/py/emit.h index ea8c3a655a6cc..f350f893436f9 100644 --- a/py/emit.h +++ b/py/emit.h @@ -193,7 +193,7 @@ typedef struct _emit_inline_asm_method_table_t { void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope, mp_obj_t *error_slot); void (*end_pass)(emit_inline_asm_t *emit); mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); - void (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); + bool (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); void (*align)(emit_inline_asm_t *emit, mp_uint_t align); void (*data)(emit_inline_asm_t *emit, mp_uint_t bytesize, mp_uint_t val); void (*op)(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index ddcd5d3947d19..220ff12c71d42 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -63,7 +63,6 @@ emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) { emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); emit->max_num_labels = max_num_labels; emit->label_lookup = m_new(qstr, max_num_labels); - memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); emit->as = asm_thumb_new(max_num_labels); return emit; } @@ -78,6 +77,9 @@ STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pa emit->pass = pass; emit->scope = scope; emit->error_slot = error_slot; + if (emit->pass == MP_PASS_CODE_SIZE) { + memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); + } asm_thumb_start_pass(emit->as, pass == MP_PASS_EMIT ? ASM_THUMB_PASS_EMIT : ASM_THUMB_PASS_COMPUTE); asm_thumb_entry(emit->as, 0); } @@ -111,10 +113,19 @@ STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint return n_params; } -STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { +STATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { assert(label_num < emit->max_num_labels); + if (emit->pass == MP_PASS_CODE_SIZE) { + // check for duplicate label on first pass + for (int i = 0; i < emit->max_num_labels; i++) { + if (emit->label_lookup[i] == label_id) { + return false; + } + } + } emit->label_lookup[label_num] = label_id; asm_thumb_label_assign(emit->as, label_num); + return true; } STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, mp_uint_t align) { @@ -378,7 +389,9 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a } else if (strcmp(op_str, "bx") == 0) { mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15); asm_thumb_op16(emit->as, 0x4700 | (r << 3)); - } else if (op_str[0] == 'b' && op_len == 3) { + } else if (op_str[0] == 'b' && (op_len == 3 + || (op_len == 5 && op_str[3] == '_' + && (op_str[4] == 'n' || op_str[4] == 'w')))) { mp_uint_t cc = -1; for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { @@ -389,7 +402,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a goto unknown_op; } int label_num = get_arg_label(emit, op_str, pn_args[0]); - if (!asm_thumb_bcc_n_label(emit->as, cc, label_num)) { + if (!asm_thumb_bcc_nw_label(emit->as, cc, label_num, op_len == 5 && op_str[4] == 'w')) { goto branch_not_in_range; } } else if (op_str[0] == 'i' && op_str[1] == 't') { diff --git a/py/modbuiltins.c b/py/modbuiltins.c index c7323afaad58a..31ed8a715964e 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -492,7 +492,7 @@ STATIC mp_obj_t mp_builtin_sum(mp_uint_t n_args, const mp_obj_t *args) { assert(1 <= n_args && n_args <= 2); mp_obj_t value; switch (n_args) { - case 1: value = mp_obj_new_int(0); break; + case 1: value = MP_OBJ_NEW_SMALL_INT(0); break; default: value = args[1]; break; } mp_obj_t iterable = mp_getiter(args[0]); diff --git a/py/mpz.c b/py/mpz.c index a056a6e8ad620..dbad14148610c 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -803,6 +803,9 @@ bool mpz_is_zero(const mpz_t *z) { return z->len == 0; } +#if 0 +these functions are unused + bool mpz_is_pos(const mpz_t *z) { return z->len > 0 && z->neg == 0; } @@ -818,6 +821,7 @@ bool mpz_is_odd(const mpz_t *z) { bool mpz_is_even(const mpz_t *z) { return z->len == 0 || (z->dig[0] & 1) == 0; } +#endif int mpz_cmp(const mpz_t *z1, const mpz_t *z2) { // to catch comparison of -0 with +0 @@ -921,6 +925,17 @@ mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) { mpz_pow_inpl(z, lhs, rhs); return z; } + +/* computes new integers in quo and rem such that: + quo * rhs + rem = lhs + 0 <= rem < rhs + can have lhs, rhs the same +*/ +void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) { + *quo = mpz_zero(); + *rem = mpz_zero(); + mpz_divmod_inpl(*quo, *rem, lhs, rhs); +} #endif /* computes dest = abs(z) @@ -1205,7 +1220,7 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { mpz_set_from_int(dest, 1); while (n->len > 0) { - if (mpz_is_odd(n)) { + if ((n->dig[0] & 1) != 0) { mpz_mul_inpl(dest, dest, x); } n->len = mpn_shr(n->dig, n->dig, n->len, 1); @@ -1219,6 +1234,9 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { mpz_free(n); } +#if 0 +these functions are unused + /* computes gcd(z1, z2) based on Knuth's modified gcd algorithm (I think?) gcd(z1, z2) >= 0 @@ -1294,17 +1312,7 @@ mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) { rem->neg = 0; return rem; } - -/* computes new integers in quo and rem such that: - quo * rhs + rem = lhs - 0 <= rem < rhs - can have lhs, rhs the same -*/ -void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) { - *quo = mpz_zero(); - *rem = mpz_zero(); - mpz_divmod_inpl(*quo, *rem, lhs, rhs); -} +#endif /* computes new integers in quo and rem such that: quo * rhs + rem = lhs diff --git a/py/mpz.h b/py/mpz.h index d52e58b0c9c42..b6d17a3f4eec2 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -102,20 +102,8 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src); mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base); bool mpz_is_zero(const mpz_t *z); -bool mpz_is_pos(const mpz_t *z); -bool mpz_is_neg(const mpz_t *z); -bool mpz_is_odd(const mpz_t *z); -bool mpz_is_even(const mpz_t *z); - int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_abs(const mpz_t *z); -mpz_t *mpz_neg(const mpz_t *z); -mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs); - void mpz_abs_inpl(mpz_t *dest, const mpz_t *z); void mpz_neg_inpl(mpz_t *dest, const mpz_t *z); void mpz_not_inpl(mpz_t *dest, const mpz_t *z); @@ -128,13 +116,7 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); - -mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2); -mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2); -void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem); void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs); -mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs); mp_int_t mpz_hash(const mpz_t *z); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); diff --git a/py/nlr.h b/py/nlr.h index 2c09de0ba4284..16cab1c667876 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -99,6 +99,7 @@ void nlr_jump_fail(void *val); nlr_jump(_val); \ } while (0) +#if !MICROPY_NLR_SETJMP #define nlr_push(val) \ assert(MP_STATE_VM(nlr_top) != val),nlr_push(val) @@ -107,6 +108,7 @@ void nlr_jump_fail(void *val); printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_VM(nlr_top), val),assert(MP_STATE_VM(nlr_top) != val),nlr_push(val) #endif */ +#endif #endif diff --git a/stmhal/Makefile b/stmhal/Makefile index c457e2ff13632..87a4637770537 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -98,6 +98,7 @@ SRC_C = \ string0.c \ system_stm32f4xx.c \ stm32f4xx_it.c \ + stm32f4xx_hal_can.c \ usbd_conf.c \ usbd_desc.c \ usbd_cdc_interface.c \ @@ -157,7 +158,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/src/,\ stm32f4xx_hal.c \ stm32f4xx_hal_adc.c \ stm32f4xx_hal_adc_ex.c \ - stm32f4xx_hal_can.c \ stm32f4xx_hal_cortex.c \ stm32f4xx_hal_dac.c \ stm32f4xx_hal_dac_ex.c \ diff --git a/stmhal/can.c b/stmhal/can.c index 654daddf6fd81..68f9729d9e1c0 100644 --- a/stmhal/can.c +++ b/stmhal/can.c @@ -349,7 +349,7 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ static const mp_arg_t allowed_args[] = { { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; // parse args @@ -383,8 +383,18 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ self->can.pTxMsg = &tx_msg; HAL_StatusTypeDef status = HAL_CAN_Transmit(&self->can, args[2].u_int); - if (status != HAL_OK) { - mp_hal_raise(status); + if (args[2].u_int != 0) { + if (status != HAL_OK) { + mp_hal_raise(status); + } + } else { + if (status == HAL_ERROR || status == HAL_BUSY) { + // HAL_CAN_Transmit returns HAL_ERROR when timeout = 0 and all three + // Tx buffers is in use. It returns HAL_BUSY when the HAL is in use + // by another thread in an RTOS environment. Here we throw a busy exception + // to make it possible for the Python code to retry the send again. + mp_hal_raise(HAL_BUSY); + } } return mp_const_none; diff --git a/stmhal/make-stmconst.py b/stmhal/make-stmconst.py index 03051c557e569..38f7a05754c37 100644 --- a/stmhal/make-stmconst.py +++ b/stmhal/make-stmconst.py @@ -29,8 +29,8 @@ class Lexer: regexs = ( ('#define hex', re.compile(r'#define +(?P[A-Z0-9_]+) +\(\(uint32_t\)(?P0x[0-9A-F]+)\)($| +/\*)')), ('#define X', re.compile(r'#define +(?P[A-Z0-9_]+) +(?P[A-Z0-9_]+)($| +/\*)')), - ('#define X+hex', re.compile(r'#define +(?P[A-Z0-9_]+) +\((?P[A-Z0-9_]+) \+ (?P0x[0-9A-F]+)\)($| +/\*)')), - ('#define typedef', re.compile(r'#define +(?P[A-Z0-9_]+) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P[A-Z0-9_]+)\)($| +/\*)')), + ('#define X+hex', re.compile(r'#define +(?P[A-Za-z0-9_]+) +\((?P[A-Z0-9_]+) \+ (?P0x[0-9A-F]+)\)($| +/\*)')), + ('#define typedef', re.compile(r'#define +(?P[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P[A-Za-z0-9_]+)\)($| +/\*)')), ('typedef struct', re.compile(r'typedef struct$')), ('{', re.compile(r'{$')), ('}', re.compile(r'}$')), diff --git a/stmhal/modstmconst.gen.c b/stmhal/modstmconst.gen.c index 3f2180ebc743c..fced5cf1a53a1 100644 --- a/stmhal/modstmconst.gen.c +++ b/stmhal/modstmconst.gen.c @@ -12,8 +12,10 @@ { MP_OBJ_NEW_QSTR(MP_QSTR_RTC), MP_OBJ_NEW_SMALL_INT(0x40002800) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WWDG), MP_OBJ_NEW_SMALL_INT(0x40002c00) }, { MP_OBJ_NEW_QSTR(MP_QSTR_IWDG), MP_OBJ_NEW_SMALL_INT(0x40003000) }, +{ MP_OBJ_NEW_QSTR(MP_QSTR_I2S2EXT), MP_OBJ_NEW_SMALL_INT(0x40003400) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SPI2), MP_OBJ_NEW_SMALL_INT(0x40003800) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SPI3), MP_OBJ_NEW_SMALL_INT(0x40003c00) }, +{ MP_OBJ_NEW_QSTR(MP_QSTR_I2S3EXT), MP_OBJ_NEW_SMALL_INT(0x40004000) }, { MP_OBJ_NEW_QSTR(MP_QSTR_USART2), MP_OBJ_NEW_SMALL_INT(0x40004400) }, { MP_OBJ_NEW_QSTR(MP_QSTR_USART3), MP_OBJ_NEW_SMALL_INT(0x40004800) }, { MP_OBJ_NEW_QSTR(MP_QSTR_UART4), MP_OBJ_NEW_SMALL_INT(0x40004c00) }, diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 39256bebbdbf4..b353fd72a9403 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -59,6 +59,7 @@ #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_EXECFILE (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 62d9d191e19f6..0fbf07a1eecdf 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -565,6 +565,8 @@ Q(I2C_OAR2) Q(I2C_SR1) Q(I2C_SR2) Q(I2C_TRISE) +Q(I2S2EXT) +Q(I2S3EXT) Q(IWDG) Q(IWDG_KR) Q(IWDG_PR) diff --git a/stmhal/hal/src/stm32f4xx_hal_can.c b/stmhal/stm32f4xx_hal_can.c similarity index 96% rename from stmhal/hal/src/stm32f4xx_hal_can.c rename to stmhal/stm32f4xx_hal_can.c index 7e018ee28032f..b132ccfe641d5 100644 --- a/stmhal/hal/src/stm32f4xx_hal_can.c +++ b/stmhal/stm32f4xx_hal_can.c @@ -641,7 +641,8 @@ HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout) { /* Change CAN state */ hcan->State = HAL_CAN_STATE_ERROR; - + + __HAL_UNLOCK(hcan); /* Return function status */ return HAL_ERROR; } diff --git a/tests/basics/boundmeth1.py b/tests/basics/boundmeth1.py new file mode 100644 index 0000000000000..a728872755a63 --- /dev/null +++ b/tests/basics/boundmeth1.py @@ -0,0 +1,24 @@ +# tests basics of bound methods + +# uPy and CPython differ when printing a bound method, so just print the type +print(type(repr([].append))) + +class A: + def f(self): + return 0 + def g(self, a): + return a + def h(self, a, b, c, d, e, f): + return a + b + c + d + e + f + +# bound method with no extra args +m = A().f +print(m()) + +# bound method with 1 extra arg +m = A().g +print(m(1)) + +# bound method with lots of extra args +m = A().h +print(m(1, 2, 3, 4, 5, 6)) diff --git a/tests/basics/builtin_allany.py b/tests/basics/builtin_allany.py new file mode 100644 index 0000000000000..07052e42fe404 --- /dev/null +++ b/tests/basics/builtin_allany.py @@ -0,0 +1,19 @@ +# test builtin "all" and "any" + +tests = ( + (), + [], + [False], + [True], + [False, True], + [True, False], + [False, False], + [True, True], + range(10), +) + +for test in tests: + print(all(test)) + +for test in tests: + print(any(test)) diff --git a/tests/basics/builtin_sum.py b/tests/basics/builtin_sum.py new file mode 100644 index 0000000000000..e45b82c3584ed --- /dev/null +++ b/tests/basics/builtin_sum.py @@ -0,0 +1,14 @@ +# test builtin "sum" + +tests = ( + (), + [], + [0], + [1], + [0, 1, 2], + range(10), +) + +for test in tests: + print(sum(test)) + print(sum(test, -2)) diff --git a/tests/basics/dict2.py b/tests/basics/dict2.py index ab6180481c9ab..ca964488d2c33 100644 --- a/tests/basics/dict2.py +++ b/tests/basics/dict2.py @@ -12,5 +12,3 @@ d2 = dict(d) print('2' in d2) print(id(d) != id(d2), d == d2) - -print(d.__getitem__('2')) diff --git a/tests/basics/dict_specialmeth.py b/tests/basics/dict_specialmeth.py new file mode 100644 index 0000000000000..7a944feacf373 --- /dev/null +++ b/tests/basics/dict_specialmeth.py @@ -0,0 +1,7 @@ +# dict object with special methods + +d = {} +d.__setitem__('2', 'two') +print(d.__getitem__('2')) +d.__delitem__('2') +print(d) diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py new file mode 100644 index 0000000000000..140c8b0a60840 --- /dev/null +++ b/tests/basics/gc1.py @@ -0,0 +1,22 @@ +# basic tests for gc module + +try: + import gc +except ImportError: + print("SKIP") + import sys + sys.exit() + +print(gc.isenabled()) +gc.disable() +print(gc.isenabled()) +gc.enable() +print(gc.isenabled()) + +gc.collect() + +if hasattr(gc, 'mem_free'): + # uPy has these extra functions + # just test they execute and return an int + assert type(gc.mem_free()) is int + assert type(gc.mem_alloc()) is int diff --git a/tests/basics/int_big_cmp.py b/tests/basics/int_big_cmp.py new file mode 100644 index 0000000000000..7cb7412bdfb19 --- /dev/null +++ b/tests/basics/int_big_cmp.py @@ -0,0 +1,10 @@ +# test bignum comparisons + +i = 1 << 65 + +print(i == 0) +print(i != 0) +print(i < 0) +print(i > 0) +print(i <= 0) +print(i >= 0) diff --git a/tests/basics/int_big_error.py b/tests/basics/int_big_error.py new file mode 100644 index 0000000000000..62ab936f9614c --- /dev/null +++ b/tests/basics/int_big_error.py @@ -0,0 +1,18 @@ +# test errors operating on bignum + +i = 1 << 65 + +try: + i << -1 +except ValueError: + print("ValueError") + +try: + len(i) +except TypeError: + print("TypeError") + +try: + 1 in i +except TypeError: + print("TypeError") diff --git a/tests/basics/int_big_unary.py b/tests/basics/int_big_unary.py new file mode 100644 index 0000000000000..fe6a48ac24a59 --- /dev/null +++ b/tests/basics/int_big_unary.py @@ -0,0 +1,8 @@ +# test bignum unary operations + +i = 1 << 65 + +print(bool(i)) +print(+i) +print(-i) +print(~i) diff --git a/tests/basics/set_specialmeth.py b/tests/basics/set_specialmeth.py new file mode 100644 index 0000000000000..76036f3ffc825 --- /dev/null +++ b/tests/basics/set_specialmeth.py @@ -0,0 +1,5 @@ +# set object with special methods + +s = {1, 2} +print(s.__contains__(1)) +print(s.__contains__(3)) diff --git a/tests/extmod/ubinascii_hexlify.py b/tests/extmod/ubinascii_hexlify.py new file mode 100644 index 0000000000000..14c37cb4be61a --- /dev/null +++ b/tests/extmod/ubinascii_hexlify.py @@ -0,0 +1,9 @@ +try: + import ubinascii as binascii +except ImportError: + import binascii + +print(binascii.hexlify(b'\x00\x01\x02\x03\x04\x05\x06\x07')) +print(binascii.hexlify(b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f')) +print(binascii.hexlify(b'\x7f\x80\xff')) +print(binascii.hexlify(b'1234ABCDabcd')) diff --git a/tests/float/complex1.py b/tests/float/complex1.py new file mode 100644 index 0000000000000..4cf7a25f6da2b --- /dev/null +++ b/tests/float/complex1.py @@ -0,0 +1,32 @@ +# test basic complex number functionality + +# constructor +print(complex(1)) +print(complex(1.2)) +print(complex(1.2j)) +print(complex("1")) +print(complex("1.2")) +print(complex("1.2j")) +print(complex(1, 2)) +print(complex(1j, 2j)) + +# unary ops +print(bool(1j)) +print(+(1j)) +#print(-(1j)) uPy doesn't print correctly + +# binary ops +print(1j + 2) +print(1j + 2j) +print(1j - 2) +print(1j - 2j) +print(1j * 2) +print(1j * 2j) +print(1j / 2) +#print(1j / 2j) uPy doesn't print correctly +#print(1j ** 2) uPy doesn't print correctly +#print(1j ** 2j) uPy doesn't print correctly + +# builtin abs +print(abs(1j)) +print(abs(1j + 2)) diff --git a/tests/float/int_big_float.py b/tests/float/int_big_float.py new file mode 100644 index 0000000000000..a5fb2700f82ab --- /dev/null +++ b/tests/float/int_big_float.py @@ -0,0 +1,13 @@ +# test bignum operation with float/complex + +i = 1 << 65 + +# this should convert to float +print("%.5g" % (i / 5)) + +# these should delegate to float +print("%.5g" % (i * 1.2)) +print("%.5g" % (i / 1.2)) + +# this should delegate to complex +print("%.5g" % (i * 1.2j).imag) diff --git a/tests/float/math_fun_special.py b/tests/float/math_fun_special.py index 970e8c4c30d24..c30085a2beba0 100644 --- a/tests/float/math_fun_special.py +++ b/tests/float/math_fun_special.py @@ -2,7 +2,8 @@ try: from math import * -except ImportError: + erf +except (ImportError, NameError): print("SKIP") import sys sys.exit() diff --git a/tests/inlineasm/asmbcc.py b/tests/inlineasm/asmbcc.py new file mode 100644 index 0000000000000..540fa6591fb9d --- /dev/null +++ b/tests/inlineasm/asmbcc.py @@ -0,0 +1,27 @@ +# test bcc instructions +# at the moment only tests beq, narrow and wide versions + +@micropython.asm_thumb +def f(r0): + mov(r1, r0) + + mov(r0, 10) + cmp(r1, 1) + beq(end) + + mov(r0, 20) + cmp(r1, 2) + beq_n(end) + + mov(r0, 30) + cmp(r1, 3) + beq_w(end) + + mov(r0, 0) + + label(end) + +print(f(0)) +print(f(1)) +print(f(2)) +print(f(3)) diff --git a/tests/inlineasm/asmbcc.py.exp b/tests/inlineasm/asmbcc.py.exp new file mode 100644 index 0000000000000..39da7d1a99ee5 --- /dev/null +++ b/tests/inlineasm/asmbcc.py.exp @@ -0,0 +1,4 @@ +0 +10 +20 +30 diff --git a/tests/micropython/const_error.py b/tests/micropython/const_error.py new file mode 100644 index 0000000000000..fa7deaaf3133f --- /dev/null +++ b/tests/micropython/const_error.py @@ -0,0 +1,6 @@ +# make sure syntax error works corrects for bad const definition + +try: + exec("a = const(x)") +except SyntaxError: + print("SyntaxError") diff --git a/tests/micropython/const_error.py.exp b/tests/micropython/const_error.py.exp new file mode 100644 index 0000000000000..8729fc4343792 --- /dev/null +++ b/tests/micropython/const_error.py.exp @@ -0,0 +1 @@ +SyntaxError diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 132da230699a1..2e6679ebff6ee 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -1,4 +1,5 @@ from pyb import CAN +import pyb CAN.initfilterbanks(14) can = CAN(1) @@ -11,19 +12,19 @@ # Catch all filter can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) -can.send('abcd', 123) +can.send('abcd', 123, timeout=5000) print(can.any(0)) print(can.recv(0)) -can.send('abcd', -1) +can.send('abcd', -1, timeout=5000) print(can.recv(0)) -can.send('abcd', 0x7FF + 1) +can.send('abcd', 0x7FF + 1, timeout=5000) print(can.recv(0)) # Test too long message try: - can.send('abcdefghi', 0x7FF) + can.send('abcdefghi', 0x7FF, timeout=5000) except ValueError: print('passed') else: @@ -39,7 +40,7 @@ print(can) try: - can.send('abcde', 0x7FF + 1) + can.send('abcde', 0x7FF + 1, timeout=5000) except ValueError: print('failed') else: @@ -95,17 +96,17 @@ def cb1a(bus, reason): can.rxcallback(0, cb0) can.rxcallback(1, cb1) -can.send('11111111',1) -can.send('22222222',2) -can.send('33333333',3) +can.send('11111111',1, timeout=5000) +can.send('22222222',2, timeout=5000) +can.send('33333333',3, timeout=5000) can.rxcallback(0, cb0a) -can.send('44444444',4) +can.send('44444444',4, timeout=5000) -can.send('55555555',5) -can.send('66666666',6) -can.send('77777777',7) +can.send('55555555',5, timeout=5000) +can.send('66666666',6, timeout=5000) +can.send('77777777',7, timeout=5000) can.rxcallback(1, cb1a) -can.send('88888888',8) +can.send('88888888',8, timeout=5000) print(can.recv(0)) print(can.recv(0)) @@ -114,9 +115,40 @@ def cb1a(bus, reason): print(can.recv(1)) print(can.recv(1)) -can.send('11111111',1) -can.send('55555555',5) +can.send('11111111',1, timeout=5000) +can.send('55555555',5, timeout=5000) print(can.recv(0)) print(can.recv(1)) +del can + +# Testing asyncronous send +can = CAN(1, CAN.LOOPBACK) +can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) + +while can.any(0): + can.recv(0) + +can.send('abcde', 1, timeout=0) +print(can.any(0)) +while not can.any(0): + pass + +print(can.recv(0)) + +try: + can.send('abcde', 2, timeout=0) + can.send('abcde', 3, timeout=0) + can.send('abcde', 4, timeout=0) + can.send('abcde', 5, timeout=0) +except OSError as e: + if str(e) == '16': + print('passed') + else: + print('failed') + +pyb.delay(500) +while can.any(0): + print(can.recv(0)) + diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index b0ede7b9f4ddf..845f6d5ba16e8 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -32,3 +32,9 @@ cb1a pending (1, 0, 0, b'11111111') (5, 0, 0, b'55555555') +False +(1, 0, 0, b'abcde') +passed +(2, 0, 0, b'abcde') +(3, 0, 0, b'abcde') +(4, 0, 0, b'abcde') diff --git a/tests/run-tests b/tests/run-tests index 62f84096398fc..e83f4342105e9 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -79,6 +79,7 @@ def run_tests(pyb, tests, args): # Remove them from the below when they work if args.emit == 'native': skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class class_super class_super_object closure1 closure2 closure_defargs del_deref del_local fun3 fun_calldblstar fun_callstar fun_callstardblstar fun_defargs fun_defargs2 fun_kwargs fun_kwonly fun_kwonlydef fun_kwvarargs fun_varargs gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send globals_del string_format string_join subclass_native2_list subclass_native2_tuple try_finally_loops try_finally_return try_reraise try_reraise2 unboundlocal with1 with_break with_continue with_return'.split()}) + skip_tests.add('basics/boundmeth1.py') # requires support for many args skip_tests.add('float/string_format.py') skip_tests.add('float/cmath_fun.py') # requires f(*args) support skip_tests.add('import/gen_context.py') diff --git a/unix/Makefile b/unix/Makefile index 509c48ddfd3fb..43b5bf2dda67e 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -136,6 +136,8 @@ minimal: coverage: @echo Make sure to run make -B $(MAKE) COPT="-O0" CFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' BUILD=build-coverage PROG=micropython_coverage + +coverage_test: coverage $(eval DIRNAME=$(notdir $(CURDIR))) cd ../tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests gcov -o build-coverage/py ../py/*.c