diff --git a/.gitignore b/.gitignore index 450bbd8639..a6295928d3 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ tests/*.out # Python cache files ###################### __pycache__/ +*.pyc # Customized Makefile/project overrides ###################### diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index be58f9332c..d209871361 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -23,14 +23,14 @@ Tab-completion is useful to find out what methods an object has. Paste mode (ctrl-E) is useful to paste a large slab of Python code into the REPL. -The ``machine`` module:: +The :mod:`machine` module:: import machine machine.freq() # get the current frequency of the CPU machine.freq(160000000) # set the CPU frequency to 160 MHz -The ``esp`` module:: +The :mod:`esp` module:: import esp @@ -40,7 +40,7 @@ The ``esp`` module:: Networking ---------- -The ``network`` module:: +The :mod:`network` module:: import network @@ -69,13 +69,13 @@ A useful function for connecting to your local WiFi network is:: pass print('network config:', wlan.ifconfig()) -Once the network is established the ``socket`` module can be used +Once the network is established the :mod:`socket ` module can be used to create and use TCP/UDP sockets as usual. Delay and timing ---------------- -Use the ``time`` module:: +Use the :mod:`time ` module:: import time @@ -165,14 +165,14 @@ Use the ``machine.ADC`` class:: SPI bus ------- -The SPI driver is implemented in software and works on all pins:: +There are two SPI drivers. One is implemented in software and works on all pins:: from machine import Pin, SPI # construct an SPI bus on the given pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second - spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) + spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) spi.init(baudrate=200000) # set the baudrate @@ -194,13 +194,13 @@ Hardware SPI ------------ The hardware SPI is faster (up to 80Mhz), but only works on following pins: -``MISO`` is gpio2, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same +``MISO`` is gpio12, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same methods as SPI, except for the pin parameters for the constructor and init (as those are fixed). - from machine import Pin, HSPI + from machine import Pin, SPI - hspi = HSPI(baudrate=800000000, polarity=0, phase=0) + hspi = SPI(0, baudrate=80000000, polarity=0, phase=0) I2C bus @@ -253,15 +253,14 @@ The OneWire driver is implemented in software and works on all pins:: ow.scan() # return a list of devices on the bus ow.reset() # reset the bus ow.readbyte() # read a byte - ow.read(5) # read 5 bytes ow.writebyte(0x12) # write a byte on the bus ow.write('123') # write bytes on the bus ow.select_rom(b'12345678') # select a specific device by its ROM code -There is a specific driver for DS18B20 devices:: +There is a specific driver for DS18S20 and DS18B20 devices:: - import time - ds = onewire.DS18B20(ow) + import time, ds18x20 + ds = ds18x20.DS18X20(ow) roms = ds.scan() ds.convert_temp() time.sleep_ms(750) diff --git a/docs/esp8266/tutorial/onewire.rst b/docs/esp8266/tutorial/onewire.rst index c90044b7a8..c2cede9e38 100644 --- a/docs/esp8266/tutorial/onewire.rst +++ b/docs/esp8266/tutorial/onewire.rst @@ -6,19 +6,19 @@ The 1-wire bus is a serial bus that uses just a single wire for communication is a very popular 1-wire device, and here we show how to use the onewire module to read from such a device. -For the following code to work you need to have at least one DS18B20 temperature +For the following code to work you need to have at least one DS18S20 or DS18B20 temperature sensor with its data line connected to GPIO12. You must also power the sensors and connect a 4.7k Ohm resistor between the data pin and the power pin. :: import time import machine - import onewire + import onewire, ds18x20 # the device is on GPIO12 dat = machine.Pin(12) # create the onewire object - ds = onewire.DS18B20(onewire.OneWire(dat)) + ds = ds18x20.DS18X20(onewire.OneWire(dat)) # scan for devices on the bus roms = ds.scan() diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst new file mode 100644 index 0000000000..65fb4014e0 --- /dev/null +++ b/docs/library/pyb.USB_HID.rst @@ -0,0 +1,28 @@ +.. currentmodule:: pyb + +class USB_HID -- USB Human Interface Device (HID) +================================================= + +The USB_HID class allows creation of an object representing the USB +Human Interface Device (HID) interface. It can be used to emulate +a peripheral such as a mouse or keyboard. + +Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface. + +Constructors +------------ + +.. class:: pyb.USB_HID() + + Create a new USB_HID object. + + +Methods +------- + +.. method:: USB_HID.send(data) + + Send data over the USB HID interface: + + - ``data`` is the data to send (a tuple/list of integers, or a + bytearray). diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 2f3e7d36bd..910b2f45b4 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -188,7 +188,7 @@ Miscellaneous functions Takes a 4-tuple (or list) and sends it to the USB host (the PC) to signal a HID mouse-motion event. - .. note:: This function is deprecated. Use pyb.USB_HID().send(...) instead. + .. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead. .. function:: info([dump_alloc_table]) @@ -254,6 +254,33 @@ Miscellaneous functions Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU. +.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse) + + If called with no arguments, return the current USB mode as a string. + + If called with ``modestr`` provided, attempts to set USB mode. + This can only be done when called from ``boot.py`` before + :meth:`pyb.main()` has been called. The following values of + ``modestr`` are understood: + + - ``None``: disables USB + - ``'VCP'``: enable with VCP (Virtual COM Port) interface + - ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class) + - ``'VCP+HID'``: enable with VCP and HID (human interface device) + + For backwards compatibility, ``'CDC'`` is understood to mean + ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). + + The ``vid`` and ``pid`` parameters allow you to specify the VID + (vendor id) and PID (product id). + + If enabling HID mode, you may also specify the HID details by + passing the ``hid`` keyword parameter. It takes a tuple of + (subclass, protocol, max packet length, polling interval, report + descriptor). By default it will set appropriate values for a USB + mouse. There is also a ``pyb.hid_keyboard`` constant, which is an + appropriate tuple for a USB keyboard. + Classes ------- @@ -277,4 +304,5 @@ Classes pyb.Switch.rst pyb.Timer.rst pyb.UART.rst + pyb.USB_HID.rst pyb.USB_VCP.rst diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 2a1429cb05..3d08ae9109 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -3,6 +3,12 @@ Quick reference for the pyboard =============================== +The below pinout is for PYBv1.0. You can also view pinouts for +other versions of the pyboard: +`PYBv1.1 `__ +or `PYBLITEv1.0-AC `__ +or `PYBLITEv1.0 `__. + .. image:: http://micropython.org/resources/pybv10-pinout.jpg :alt: PYBv1.0 pinout :width: 700px @@ -14,14 +20,25 @@ See :mod:`pyb`. :: import pyb - pyb.delay(50) # wait 50 milliseconds - pyb.millis() # number of milliseconds since bootup pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1) pyb.wfi() # pause CPU, waiting for interrupt pyb.freq() # get CPU and bus frequencies pyb.freq(60000000) # set CPU freq to 60MHz pyb.stop() # stop CPU, waiting for external interrupt +Delay and timing +---------------- + +Use the :mod:`time ` module:: + + import time + + time.sleep(1) # sleep for 1 second + time.sleep_ms(500) # sleep for 500 milliseconds + time.sleep_us(10) # sleep for 10 microseconds + start = time.ticks_ms() # get value of millisecond counter + delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference + LEDs ---- diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index ac1de6e275..6f8831edb4 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -13,23 +13,23 @@ will look something like this:: import pyb #pyb.main('main.py') # main script to run after this one - #pyb.usb_mode('CDC+MSC') # act as a serial and a storage device - #pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + #pyb.usb_mode('VCP+MSC') # act as a serial and a storage device + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse To enable the mouse mode, uncomment the last line of the file, to make it look like:: - pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + pyb.usb_mode('VCP+HID') # act as a serial device and a mouse If you already changed your ``boot.py`` file, then the minimum code it needs to work is:: import pyb - pyb.usb_mode('CDC+HID') + pyb.usb_mode('VCP+HID') -This tells the pyboard to configure itself as a CDC (serial) and HID -(human interface device, in our case a mouse) USB device when it boots -up. +This tells the pyboard to configure itself as a VCP (Virtual COM Port, +ie serial port) and HID (human interface device, in our case a mouse) +USB device when it boots up. Eject/unmount the pyboard drive and reset it using the RST switch. Your PC should now detect the pyboard as a mouse! @@ -41,7 +41,8 @@ To get the py-mouse to do anything we need to send mouse events to the PC. We will first do this manually using the REPL prompt. Connect to your pyboard using your serial program and type the following:: - >>> pyb.hid((0, 10, 0, 0)) + >>> hid = pyb.USB_HID() + >>> hid.send((0, 10, 0, 0)) Your mouse should move 10 pixels to the right! In the command above you are sending 4 pieces of information: button status, x, y and scroll. The @@ -52,7 +53,7 @@ Let's make the mouse oscillate left and right:: >>> import math >>> def osc(n, d): ... for i in range(n): - ... pyb.hid((0, int(20 * math.sin(i / 10)), 0, 0)) + ... hid.send((0, int(20 * math.sin(i / 10)), 0, 0)) ... pyb.delay(d) ... >>> osc(100, 50) @@ -100,9 +101,10 @@ In ``main.py`` put the following code:: switch = pyb.Switch() accel = pyb.Accel() + hid = pyb.USB_HID() while not switch(): - pyb.hid((0, accel.x(), accel.y(), 0)) + hid.send((0, accel.x(), accel.y(), 0)) pyb.delay(20) Save your file, eject/unmount your pyboard drive, and reset it using the RST @@ -112,7 +114,7 @@ the mouse around. Try it out, and see if you can make the mouse stand still! Press the USR switch to stop the mouse motion. You'll note that the y-axis is inverted. That's easy to fix: just put a -minus sign in front of the y-coordinate in the ``pyb.hid()`` line above. +minus sign in front of the y-coordinate in the ``hid.send()`` line above. Restoring your pyboard to normal -------------------------------- @@ -121,9 +123,9 @@ If you leave your pyboard as-is, it'll behave as a mouse everytime you plug it in. You probably want to change it back to normal. To do this you need to first enter safe mode (see above), and then edit the ``boot.py`` file. In the ``boot.py`` file, comment out (put a # in front of) the line with the -``CDC+HID`` setting, so it looks like:: +``VCP+HID`` setting, so it looks like:: - #pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse Save your file, eject/unmount the drive, and reset the pyboard. It is now back to normal operating mode. diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fba383ae39..fc7a8af7c5 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -4,31 +4,41 @@ Micro Python driver for SD cards using SPI bus. Requires an SPI bus and a CS pin. Provides readblocks and writeblocks methods so the device can be mounted as a filesystem. -Example usage: +Example usage on pyboard: import pyb, sdcard, os sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) pyb.mount(sd, '/sd2') os.listdir('/') +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) + os.umount() + os.VfsFat(sd, "") + os.listdir() + """ -import pyb +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +#R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +#R1_COM_CRC_ERROR = const(1 << 3) +#R1_ERASE_SEQUENCE_ERROR = const(1 << 4) +#R1_ADDRESS_ERROR = const(1 << 5) +#R1_PARAMETER_ERROR = const(1 << 6) +_TOKEN_CMD25 = const(0xfc) +_TOKEN_STOP_TRAN = const(0xfd) +_TOKEN_DATA = const(0xfe) + class SDCard: - CMD_TIMEOUT = const(100) - - R1_IDLE_STATE = const(1 << 0) - #R1_ERASE_RESET = const(1 << 1) - R1_ILLEGAL_COMMAND = const(1 << 2) - #R1_COM_CRC_ERROR = const(1 << 3) - #R1_ERASE_SEQUENCE_ERROR = const(1 << 4) - #R1_ADDRESS_ERROR = const(1 << 5) - #R1_PARAMETER_ERROR = const(1 << 6) - TOKEN_CMD25 = const(0xfc) - TOKEN_STOP_TRAN = const(0xfd) - TOKEN_DATA = const(0xfe) - def __init__(self, spi, cs): self.spi = spi self.cs = cs @@ -42,30 +52,39 @@ class SDCard: # initialise the card self.init_card() + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + def init_card(self): # init CS pin - self.cs.high() - self.cs.init(self.cs.OUT_PP) + self.cs.init(self.cs.OUT, value=1) # init SPI bus; use low data rate for initialisation - self.spi.init(self.spi.MASTER, baudrate=100000, phase=0, polarity=0) + self.init_spi(100000) # clock card at least 100 cycles with cs high for i in range(16): - self.spi.send(0xff) + self.spi.write(b'\xff') - # CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts) + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) for _ in range(5): - if self.cmd(0, 0, 0x95) == R1_IDLE_STATE: + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: break else: raise OSError("no SD card") # CMD8: determine card version r = self.cmd(8, 0x01aa, 0x87, 4) - if r == R1_IDLE_STATE: + if r == _R1_IDLE_STATE: self.init_card_v2() - elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND): + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): self.init_card_v1() else: raise OSError("couldn't determine SD card version") @@ -86,10 +105,10 @@ class SDCard: raise OSError("can't set 512 block size") # set to high data rate now that it's initialised - self.spi.init(self.spi.MASTER, baudrate=1320000, phase=0, polarity=0) + self.init_spi(1320000) def init_card_v1(self): - for i in range(CMD_TIMEOUT): + for i in range(_CMD_TIMEOUT): self.cmd(55, 0, 0) if self.cmd(41, 0, 0) == 0: self.cdv = 512 @@ -98,8 +117,8 @@ class SDCard: raise OSError("timeout waiting for v1 card") def init_card_v2(self): - for i in range(CMD_TIMEOUT): - pyb.delay(50) + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) self.cmd(58, 0, 0, 4) self.cmd(55, 0, 0) if self.cmd(41, 0x40000000, 0) == 0: @@ -120,87 +139,87 @@ class SDCard: buf[3] = arg >> 8 buf[4] = arg buf[5] = crc - self.spi.send(buf) + self.spi.write(buf) # wait for the repsonse (response[7] == 0) - for i in range(CMD_TIMEOUT): - response = self.spi.send_recv(0xff)[0] + for i in range(_CMD_TIMEOUT): + response = self.spi.read(1, 0xff)[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): - self.spi.send(0xff) + self.spi.write(b'\xff') if release: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return response # timeout self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return -1 def cmd_nodata(self, cmd): - self.spi.send(cmd) - self.spi.send_recv(0xff) # ignore stuff byte - for _ in range(CMD_TIMEOUT): - if self.spi.send_recv(0xff)[0] == 0xff: + self.spi.write(cmd) + self.spi.read(1, 0xff) # ignore stuff byte + for _ in range(_CMD_TIMEOUT): + if self.spi.read(1, 0xff)[0] == 0xff: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 0 # OK self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 1 # timeout def readinto(self, buf): self.cs.low() # read until start byte (0xff) - while self.spi.send_recv(0xff)[0] != 0xfe: + while self.spi.read(1, 0xff)[0] != 0xfe: pass # read data mv = self.dummybuf_memoryview[:len(buf)] - self.spi.send_recv(mv, recv=buf) + self.spi.write_readinto(mv, buf) # read checksum - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.write(b'\xff') + self.spi.write(b'\xff') self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write(self, token, buf): self.cs.low() # send: start of block, data, checksum - self.spi.send(token) - self.spi.send(buf) - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b'\xff') + self.spi.write(b'\xff') # check the response - if (self.spi.send_recv(0xff)[0] & 0x1f) != 0x05: + if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write_token(self, token): self.cs.low() - self.spi.send(token) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(b'\xff') # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0x00: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def count(self): return self.sectors @@ -224,7 +243,7 @@ class SDCard: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(12) + return self.cmd_nodata(b'\x0c') # cmd 12 return 0 def writeblocks(self, block_num, buf): @@ -236,7 +255,7 @@ class SDCard: return 1 # send the data - self.write(TOKEN_DATA, buf) + self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: @@ -245,8 +264,8 @@ class SDCard: offset = 0 mv = memoryview(buf) while nblocks: - self.write(TOKEN_CMD25, mv[offset : offset + 512]) + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) offset += 512 nblocks -= 1 - self.write_token(TOKEN_STOP_TRAN) + self.write_token(_TOKEN_STOP_TRAN) return 0 diff --git a/esp8266/Makefile b/esp8266/Makefile index 0b498602f2..2786510388 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -78,6 +78,7 @@ SRC_C = \ modpybrtc.c \ modpybadc.c \ modpybuart.c \ + modmachinewdt.c \ modmachinespi.c \ modpybspi.c \ modpybhspi.c \ @@ -140,7 +141,7 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) OBJ = diff --git a/esp8266/hspi.c b/esp8266/hspi.c index 7315dc8a12..436fb4f6f4 100644 --- a/esp8266/hspi.c +++ b/esp8266/hspi.c @@ -199,7 +199,11 @@ uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, // This is rather inefficient but allows for a very generic function. // CMD ADDR and MOSI are set below to save on an extra if statement. if (din_bits) { - SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + if (dout_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); + } else { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + } } if (dummy_bits) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 7672834aac..0972ce29fb 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -49,6 +49,8 @@ //#define MACHINE_WAKE_SLEEP (0x02) #define MACHINE_WAKE_DEEPSLEEP (0x04) +extern const mp_obj_type_t esp_wdt_type; + STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -246,6 +248,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, diff --git a/esp8266/modmachinewdt.c b/esp8266/modmachinewdt.c new file mode 100644 index 0000000000..e0b1ff5d78 --- /dev/null +++ b/esp8266/modmachinewdt.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//#include +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "user_interface.h" + +const mp_obj_type_t esp_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + return &wdt_default; + default: + mp_raise_ValueError(""); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + system_soft_wdt_feed(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj } +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t esp_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_t)&machine_wdt_locals_dict, +}; diff --git a/esp8266/modpybhspi.c b/esp8266/modpybhspi.c index f80fbae00a..c4d4dcee8d 100644 --- a/esp8266/modpybhspi.c +++ b/esp8266/modpybhspi.c @@ -35,6 +35,7 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" #include "hspi.h" @@ -47,6 +48,58 @@ typedef struct _pyb_hspi_obj_t { } pyb_hspi_obj_t; +STATIC void hspi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + (void)self_in; + + if (dest_len == 0) { + // fast case when we only need to write data + size_t chunk_size = 1024; + size_t count = src_len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + spi_tx8fast(HSPI, src_buf[i]); + ++i; + } + ets_loop_iter(); + } + while (i < src_len) { + spi_tx8fast(HSPI, src_buf[i]); + ++i; + } + } else { + // we need to read and write data + + // Process data in chunks, let the pending tasks run in between + size_t chunk_size = 1024; // TODO this should depend on baudrate + size_t count = dest_len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + uint32_t data_out; + if (src_len == 1) { + data_out = src_buf[0]; + } else { + data_out = src_buf[i]; + } + dest_buf[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out, 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < dest_len) { + uint32_t data_out; + if (src_len == 1) { + data_out = src_buf[0]; + } else { + data_out = src_buf[i]; + } + dest_buf[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out, 8, 0); + ++i; + } + } +} + /******************************************************************************/ // MicroPython bindings for HSPI @@ -126,133 +179,25 @@ STATIC mp_obj_t pyb_hspi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_ } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_hspi_init_obj, 1, pyb_hspi_init); - -STATIC mp_obj_t pyb_hspi_read(size_t n_args, const mp_obj_t *args) { - vstr_t dest_buf; - vstr_init_len(&dest_buf, mp_obj_get_int(args[1])); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - // Process data in chunks, let the pending tasks run in between - size_t chunk_size = 1024; // TODO this should depend on baudrate - size_t count = dest_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < dest_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - return mp_obj_new_str_from_vstr(&mp_type_bytes, &dest_buf); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_read_obj, 2, 3, pyb_hspi_read); - - -STATIC mp_obj_t pyb_hspi_readinto(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(args[1], &dest_buf, MP_BUFFER_WRITE); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - - size_t chunk_size = 1024; - size_t count = dest_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < dest_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_readinto_obj, 2, 3, pyb_hspi_readinto); - - -STATIC mp_obj_t pyb_hspi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) { - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - - size_t chunk_size = 1024; - size_t count = src_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); - ++i; - } - ets_loop_iter(); - } - while (i < src_buf.len) { - spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pyb_hspi_write_obj, pyb_hspi_write); - - -STATIC mp_obj_t pyb_hspi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) { - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE); - if (src_buf.len != dest_buf.len) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "buffers must be the same length")); - } - - size_t chunk_size = 1024; - size_t count = src_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < src_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_3(pyb_hspi_write_readinto_obj, pyb_hspi_write_readinto); - - STATIC const mp_rom_map_elem_t pyb_hspi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_hspi_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_hspi_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_hspi_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_hspi_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_hspi_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_hspi_locals_dict, pyb_hspi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_hspi_p = { + .transfer = hspi_transfer, +}; + const mp_obj_type_t pyb_hspi_type = { { &mp_type_type }, .name = MP_QSTR_HSPI, .print = pyb_hspi_print, .make_new = pyb_hspi_make_new, + .protocol = &pyb_hspi_p, .locals_dict = (mp_obj_dict_t*)&pyb_hspi_locals_dict, }; diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c index 9685248034..500b2bc545 100644 --- a/esp8266/modpybrtc.c +++ b/esp8266/modpybrtc.c @@ -212,7 +212,7 @@ STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time } // set expiry time (in microseconds) - pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000; + pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000; return mp_const_none; diff --git a/esp8266/modpybspi.c b/esp8266/modpybspi.c index fafe3b2fa5..4c4b843c5d 100644 --- a/esp8266/modpybspi.c +++ b/esp8266/modpybspi.c @@ -35,6 +35,7 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" typedef struct _pyb_spi_obj_t { mp_obj_base_t base; @@ -46,7 +47,8 @@ typedef struct _pyb_spi_obj_t { mp_hal_pin_obj_t miso; } pyb_spi_obj_t; -STATIC void mp_hal_spi_transfer(pyb_spi_obj_t *self, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { +STATIC void mp_hal_spi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; // only MSB transfer is implemented uint32_t delay_half = 500000 / self->baudrate + 1; for (size_t i = 0; i < src_len || i < dest_len; ++i) { @@ -154,69 +156,25 @@ STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_a } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init); -STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *args) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - vstr_t vstr; - vstr_init_len(&vstr, mp_obj_get_int(args[1])); - mp_hal_spi_transfer(self, 1, &write_byte, vstr.len, (uint8_t*)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_read_obj, 2, 3, pyb_spi_read); - -STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *args) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - mp_hal_spi_transfer(self, 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_readinto_obj, 2, 3, pyb_spi_readinto); - -STATIC mp_obj_t pyb_spi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, 0, NULL); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); - -STATIC mp_obj_t pyb_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE); - if (src_buf.len != dest_buf.len) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length")); - } - mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, dest_buf.len, (uint8_t*)dest_buf.buf); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto); - STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_spi_p = { + .transfer = mp_hal_spi_transfer, +}; + const mp_obj_type_t pyb_spi_type = { { &mp_type_type }, .name = MP_QSTR_SoftSPI, .print = pyb_spi_print, .make_new = pyb_spi_make_new, + .protocol = &pyb_spi_p, .locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict, }; diff --git a/esp8266/modules/ds18x20.py b/esp8266/modules/ds18x20.py new file mode 100644 index 0000000000..eb22e2ae30 --- /dev/null +++ b/esp8266/modules/ds18x20.py @@ -0,0 +1,46 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +_CONVERT = const(0x44) +_RD_SCRATCH = const(0xbe) +_WR_SCRATCH = const(0x4e) + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception('CRC error') + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xff) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + return (buf[1] << 8 | buf[0]) / 16 diff --git a/esp8266/scripts/onewire.py b/esp8266/modules/onewire.py similarity index 66% rename from esp8266/scripts/onewire.py rename to esp8266/modules/onewire.py index 686616950a..06b216a57a 100644 --- a/esp8266/scripts/onewire.py +++ b/esp8266/modules/onewire.py @@ -15,8 +15,11 @@ class OneWire: self.pin = pin self.pin.init(pin.OPEN_DRAIN) - def reset(self): - return _ow.reset(self.pin) + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset def readbit(self): return _ow.readbit(self.pin) @@ -24,11 +27,9 @@ class OneWire: def readbyte(self): return _ow.readbyte(self.pin) - def read(self, count): - buf = bytearray(count) - for i in range(count): + def readinto(self, buf): + for i in range(len(buf)): buf[i] = _ow.readbyte(self.pin) - return buf def writebit(self, value): return _ow.writebit(self.pin, value) @@ -87,41 +88,3 @@ class OneWire: def crc8(self, data): return _ow.crc8(data) - -class DS18B20: - CONVERT = const(0x44) - RD_SCRATCH = const(0xbe) - WR_SCRATCH = const(0x4e) - - def __init__(self, onewire): - self.ow = onewire - - def scan(self): - return [rom for rom in self.ow.scan() if rom[0] == 0x28] - - def convert_temp(self): - if not self.ow.reset(): - raise OneWireError - self.ow.writebyte(SKIP_ROM) - self.ow.writebyte(CONVERT) - - def read_scratch(self, rom): - if not self.ow.reset(): - raise OneWireError - self.ow.select_rom(rom) - self.ow.writebyte(RD_SCRATCH) - buf = self.ow.read(9) - if self.ow.crc8(buf): - raise OneWireError - return buf - - def write_scratch(self, rom, buf): - if not self.ow.reset(): - raise OneWireError - self.ow.select_rom(rom) - self.ow.writebyte(WR_SCRATCH) - self.ow.write(buf) - - def read_temp(self, rom): - buf = self.read_scratch(rom) - return (buf[1] << 8 | buf[0]) / 16 diff --git a/esp8266/moduos.c b/esp8266/moduos.c index af149625d6..bbbf2b6b8b 100644 --- a/esp8266/moduos.c +++ b/esp8266/moduos.c @@ -123,6 +123,10 @@ STATIC mp_obj_t os_rename(mp_obj_t path_old, mp_obj_t path_new) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename); +STATIC mp_obj_t os_umount(void) { + return vfs_proxy_call(MP_QSTR_umount, 0, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_umount_obj, os_umount); #endif STATIC mp_obj_t os_urandom(mp_obj_t num) { @@ -166,6 +170,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&os_umount_obj) }, #endif }; diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 63b9258a20..4fc8d856b6 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -63,6 +63,7 @@ #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_WEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) diff --git a/examples/SDdatalogger/boot.py b/examples/SDdatalogger/boot.py index aa943fde93..4ac94bbaa4 100644 --- a/examples/SDdatalogger/boot.py +++ b/examples/SDdatalogger/boot.py @@ -16,10 +16,10 @@ pyb.LED(3).off() # indicate that we finished waiting for the swit pyb.LED(4).on() # indicate that we are selecting the mode if switch_value: - pyb.usb_mode('CDC+MSC') + pyb.usb_mode('VCP+MSC') pyb.main('cardreader.py') # if switch was pressed, run this else: - pyb.usb_mode('CDC+HID') + pyb.usb_mode('VCP+HID') pyb.main('datalogger.py') # if switch wasn't pressed, run this pyb.LED(4).off() # indicate that we finished selecting the mode diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index 9ddc98f3dd..cbc1e36220 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -162,7 +162,7 @@ STATIC mp_obj_t fatfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k } MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount); -STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { +mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { size_t i = 0; if (MP_OBJ_IS_STR(bdev_or_path_in)) { mp_uint_t mnt_len; diff --git a/extmod/fsusermount.h b/extmod/fsusermount.h index a25434b781..e1f26f2ce8 100644 --- a/extmod/fsusermount.h +++ b/extmod/fsusermount.h @@ -55,6 +55,7 @@ typedef struct _fs_user_mount_t { } fs_user_mount_t; fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs); +mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in); MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj); MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj); diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c new file mode 100644 index 0000000000..6b6202a221 --- /dev/null +++ b/extmod/machine_spi.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "extmod/machine_spi.h" + +#if MICROPY_PY_MACHINE_SPI + +STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest) { + mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol; + spi_p->transfer(s, slen, src, dlen, dest); +} + +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + mp_machine_spi_transfer(args[0], 1, &write_byte, vstr.len, (uint8_t*)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + mp_machine_spi_transfer(args[0], 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, 0, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length")); + } + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, dest.len, (uint8_t*)dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h new file mode 100644 index 0000000000..26d716fc11 --- /dev/null +++ b/extmod/machine_spi.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H + +#include "py/obj.h" + +// SPI protocol +typedef struct _mp_machine_spi_p_t { + void (*transfer)(mp_obj_base_t *obj, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest); +} mp_machine_spi_p_t; + +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_read_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_readinto_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index d0ef238075..84f1246fba 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -68,7 +68,8 @@ STATIC mp_obj_t framebuf1_fill(mp_obj_t self_in, mp_obj_t col_in) { if (col) { col = 0xff; } - for (int y = 0; y < self->height / 8; ++y) { + int end = (self->height + 7) >> 3; + for (int y = 0; y < end; ++y) { memset(self->buf + y * self->stride, col, self->width); } return mp_const_none; @@ -83,7 +84,7 @@ STATIC mp_obj_t framebuf1_pixel(size_t n_args, const mp_obj_t *args) { int index = (y / 8) * self->stride + x; if (n_args == 3) { // get - return MP_OBJ_NEW_SMALL_INT(self->buf[index] >> (y & 7)); + return MP_OBJ_NEW_SMALL_INT((self->buf[index] >> (y & 7)) & 1); } else { // set if (mp_obj_get_int(args[3])) { @@ -101,8 +102,9 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t xstep = mp_obj_get_int(xstep_in); mp_int_t ystep = mp_obj_get_int(ystep_in); + int end = (self->height + 7) >> 3; if (xstep == 0 && ystep > 0) { - for (int y = self->height / 8; y > 0;) { + for (int y = end; y > 0;) { --y; for (int x = 0; x < self->width; ++x) { int prev = 0; @@ -113,10 +115,10 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y } } } else if (xstep == 0 && ystep < 0) { - for (int y = 0; y < self->height / 8; ++y) { + for (int y = 0; y < end; ++y) { for (int x = 0; x < self->width; ++x) { int prev = 0; - if (y + 1 < self->height / 8) { + if (y + 1 < end) { prev = self->buf[(y + 1) * self->stride + x] << (8 + ystep); } self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] >> -ystep) | prev; diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 3cceb991f1..562c754b52 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -33,6 +33,7 @@ #include "py/binary.h" #include "extmod/modubinascii.h" +#include "uzlib/tinf.h" mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { // Second argument is for an extension to allow a separator to be used @@ -203,6 +204,17 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) { } MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); +#if MICROPY_PY_UBINASCII_CRC32 +mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + uint32_t crc = (n_args > 1) ? mp_obj_get_int(args[1]) : 0; + crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); + return MP_OBJ_NEW_SMALL_INT(crc ^ 0xffffffff); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); +#endif + #if MICROPY_PY_UBINASCII STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { @@ -211,6 +223,9 @@ STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) }, { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) }, { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) }, + #if MICROPY_PY_UBINASCII_CRC32 + { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table); diff --git a/extmod/modubinascii.h b/extmod/modubinascii.h index 0f9b82c1cb..71dd8a6936 100644 --- a/extmod/modubinascii.h +++ b/extmod/modubinascii.h @@ -31,10 +31,12 @@ extern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args); extern mp_obj_t mod_binascii_unhexlify(mp_obj_t data); extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data); extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data); +extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_hexlify_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_unhexlify_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_a2b_base64_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_b2a_base64_obj); +MP_DECLARE_CONST_FUN_OBJ(mod_binascii_crc32_obj); #endif /* MICROPY_EXTMOD_MODUBINASCII */ diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index b733ae2e04..dbf513527a 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,8 @@ #include "py/nlr.h" #include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" #if MICROPY_PY_UZLIB @@ -40,6 +42,85 @@ #define DEBUG_printf(...) (void)0 #endif +typedef struct _mp_obj_decompio_t { + mp_obj_base_t base; + mp_obj_t src_stream; + TINF_DATA decomp; + bool eof; +} mp_obj_decompio_t; + +STATIC unsigned char read_src_stream(TINF_DATA *data) { + byte *p = (void*)data; + p -= offsetof(mp_obj_decompio_t, decomp); + mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; + + const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ); + int err; + byte c; + mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); + if (out_sz == MP_STREAM_ERROR) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); + } + if (out_sz == 0) { + nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); + } + return c; +} + +#define DICT_SIZE 32768 + +STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); + o->base.type = type; + memset(&o->decomp, 0, sizeof(o->decomp)); + uzlib_uncompress_init(&o->decomp, m_new(byte, DICT_SIZE), DICT_SIZE); + o->decomp.readSource = read_src_stream; + o->src_stream = args[0]; + o->eof = false; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in); + if (o->eof) { + return 0; + } + + o->decomp.dest = buf; + o->decomp.destSize = size; + int st = uzlib_uncompress_chksum(&o->decomp); + if (st == TINF_DONE) { + o->eof = true; + } + if (st < 0) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + return o->decomp.dest - (byte*)buf; +} + +STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); + +STATIC const mp_stream_p_t decompio_stream_p = { + .read = decompio_read, +}; + +STATIC const mp_obj_type_t decompio_type = { + { &mp_type_type }, + .name = MP_QSTR_DecompIO, + .make_new = decompio_make_new, + .protocol = &decompio_stream_p, + .locals_dict = (void*)&decompio_locals_dict, +}; + STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_t data = args[0]; @@ -102,6 +183,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_u STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) }, + { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index a691ee062c..eea075f6b0 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -250,6 +250,13 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); +// Unmount the filesystem +STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { + fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount); + STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, @@ -261,6 +268,7 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/lib/berkeley-db-1.xx b/lib/berkeley-db-1.xx index 78a4787948..dab957dacd 160000 --- a/lib/berkeley-db-1.xx +++ b/lib/berkeley-db-1.xx @@ -1 +1 @@ -Subproject commit 78a4787948bb80cbfafcfd7910f95f61a4dd0d4c +Subproject commit dab957dacddcbf6cbc85d42df62e189e4877bb72 diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 411ee969d6..2bc7a00cc0 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -112,7 +112,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, printf("took " UINT_FMT " ms\n", ticks); // qstr info { - mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); } diff --git a/lib/utils/stdout_helpers.c b/lib/utils/stdout_helpers.c index 6efe10b92c..5f7a17d320 100644 --- a/lib/utils/stdout_helpers.c +++ b/lib/utils/stdout_helpers.c @@ -11,7 +11,7 @@ // Send "cooked" string of given length, where every occurance of // LF character is replaced with CR LF. -void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { while (len--) { if (*str == '\n') { mp_hal_stdout_tx_strn("\r", 1); diff --git a/py/bc.c b/py/bc.c index 5cdaa4770d..0d0a0b12f9 100644 --- a/py/bc.c +++ b/py/bc.c @@ -89,7 +89,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // - code_state->ip should contain the offset in bytes from the start of // the bytecode chunk to just after n_state and n_exc_stack // - code_state->n_state should be set to the state size (locals plus stack) -void mp_setup_code_state(mp_code_state *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { +void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. size_t n_state = code_state->n_state; diff --git a/py/bc.h b/py/bc.h index c2d95bedde..4707da1793 100644 --- a/py/bc.h +++ b/py/bc.h @@ -60,7 +60,7 @@ // constN : obj // Exception stack entry -typedef struct _mp_exc_stack { +typedef struct _mp_exc_stack_t { const byte *handler; // bit 0 is saved currently_in_except_block value // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY @@ -69,7 +69,7 @@ typedef struct _mp_exc_stack { mp_obj_base_t *prev_exc; } mp_exc_stack_t; -typedef struct _mp_code_state { +typedef struct _mp_code_state_t { const byte *code_info; const byte *ip; const mp_uint_t *const_table; @@ -78,21 +78,21 @@ typedef struct _mp_code_state { mp_exc_stack_t *exc_sp; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS - struct _mp_code_state *prev; + struct _mp_code_state_t *prev; #endif size_t n_state; // Variable-length mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) //mp_exc_stack_t exc_state[0]; -} mp_code_state; +} mp_code_state_t; mp_uint_t mp_decode_uint(const byte **ptr); -mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc); -mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); struct _mp_obj_fun_bc_t; -void mp_setup_code_state(mp_code_state *code_state, struct _mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_setup_code_state(mp_code_state_t *code_state, struct _mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const byte *code, mp_uint_t len); const byte *mp_bytecode_print_str(const byte *ip); diff --git a/py/compile.c b/py/compile.c index df6dab063c..c8b4e5470d 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1200,6 +1200,11 @@ STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) } STATIC void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // with optimisations enabled we don't compile assertions + if (MP_STATE_VM(mp_optimise_value) != 0) { + return; + } + uint l_end = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], true, l_end); EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython diff --git a/py/emitglue.c b/py/emitglue.c index 1b9992b8e1..0b5903092a 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -348,12 +348,10 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { byte header[4]; read_bytes(reader, header, sizeof(header)); if (strncmp((char*)header, "M\x00", 2) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "invalid .mpy file")); + mp_raise_ValueError("invalid .mpy file"); } if (header[2] != MPY_FEATURE_FLAGS || header[3] > mp_small_int_bits()) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "incompatible .mpy file")); + mp_raise_ValueError("incompatible .mpy file"); } return load_raw_code(reader); } @@ -559,8 +557,7 @@ STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *i STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { if (rc->kind != MP_CODE_BYTECODE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "can only save bytecode")); + mp_raise_ValueError("can only save bytecode"); } // save bytecode diff --git a/py/emitnative.c b/py/emitnative.c index 9adaabc11c..2cf4711feb 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -628,7 +628,7 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg); STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -#define STATE_START (sizeof(mp_code_state) / sizeof(mp_uint_t)) +#define STATE_START (sizeof(mp_code_state_t) / sizeof(mp_uint_t)) STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); @@ -775,10 +775,10 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state, ip) / sizeof(mp_uint_t), REG_ARG_1); + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(mp_uint_t), REG_ARG_1); // set code_state.n_state - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state, n_state) / sizeof(mp_uint_t), REG_ARG_1); + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state_t, n_state) / sizeof(mp_uint_t), REG_ARG_1); // put address of code_state into first arg ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); diff --git a/py/gc.c b/py/gc.c index 97868c07f8..7ed53cfc7f 100644 --- a/py/gc.c +++ b/py/gc.c @@ -480,12 +480,17 @@ found: GC_EXIT(); + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK); + #else // zero out the additional bytes of the newly allocated blocks // This is needed because the blocks may have previously held pointers // to the heap and will not be set to something else if the caller // doesn't actually use the entire block. As such they will continue // to point to the heap and may prevent other blocks from being reclaimed. memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes); + #endif #if MICROPY_ENABLE_FINALISER if (has_finaliser) { @@ -713,8 +718,13 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { GC_EXIT(); + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK); + #else // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc) memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes); + #endif #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 8a3136b1f1..7249769f47 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -14,11 +14,13 @@ import sys # - codepoint2name lives in a different module import platform if platform.python_version_tuple()[0] == '2': - ord_bytes = ord + bytes_cons = lambda val, enc=None: bytearray(val) from htmlentitydefs import codepoint2name elif platform.python_version_tuple()[0] == '3': - ord_bytes = lambda x:x + bytes_cons = bytes from html.entities import codepoint2name +# end compatibility code + codepoint2name[ord('-')] = 'hyphen'; # add some custom names to map characters that aren't in HTML @@ -52,8 +54,8 @@ codepoint2name[ord('~')] = 'tilde' # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): hash = 5381 - for char in qstr: - hash = (hash * 33) ^ ord(char) + for b in qstr: + hash = (hash * 33) ^ b # Make sure that valid hash is never zero, zero means "hash not computed" return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1 @@ -115,16 +117,15 @@ def parse_input_headers(infiles): return qcfgs, qstrs def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): - qhash = compute_hash(qstr, cfg_bytes_hash) + qbytes = bytes_cons(qstr, 'utf8') + qlen = len(qbytes) + qhash = compute_hash(qbytes, cfg_bytes_hash) if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): # qstr is all printable ASCII so render it as-is (for easier debugging) - qlen = len(qstr) qdata = qstr else: # qstr contains non-printable codes so render entire thing as hex pairs - qbytes = qstr.encode('utf8') - qlen = len(qbytes) - qdata = ''.join(('\\x%02x' % ord_bytes(b)) for b in qbytes) + qdata = ''.join(('\\x%02x' % b) for b in qbytes) if qlen >= (1 << (8 * cfg_bytes_len)): print('qstr is too long:', qstr) assert False diff --git a/py/malloc.c b/py/malloc.c index b0493d9341..f48cb8da4f 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -117,7 +117,10 @@ void *m_malloc0(size_t num_bytes) { if (ptr == NULL && num_bytes != 0) { return m_malloc_fail(num_bytes); } + // If this config is set then the GC clears all memory, so we don't need to. + #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(ptr, 0, num_bytes); + #endif return ptr; } diff --git a/py/mkrules.mk b/py/mkrules.mk index 3cf0e30584..a3a408dc89 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -123,8 +123,9 @@ clean-prog: .PHONY: clean-prog endif -lib: $(OBJ) - $(AR) rcs libmicropython.a $^ +LIBMICROPYTHON = libmicropython.a +lib $(LIBMICROPYTHON): $(OBJ) + $(AR) rcs $(LIBMICROPYTHON) $^ clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) diff --git a/py/modstruct.c b/py/modstruct.c index 2016add17e..be0d0110de 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -114,7 +114,7 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { mp_uint_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); if (sz == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "unsupported format")); + mp_raise_ValueError("unsupported format"); } while (cnt--) { // Apply alignment @@ -149,7 +149,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = bufinfo.len + offset; if (offset < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } } p += offset; @@ -164,7 +164,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { sz = get_fmt_num(&fmt); } if (p + sz > end_p) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } mp_obj_t item; if (*fmt == 's') { @@ -197,7 +197,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, siz sz = get_fmt_num(&fmt); } if (p + sz > end_p) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } if (*fmt == 's') { @@ -240,7 +240,7 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = (mp_int_t)bufinfo.len + offset; if (offset < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } } byte *p = (byte *)bufinfo.buf; diff --git a/py/mpconfig.h b/py/mpconfig.h index 3808df7430..455f870ac7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -107,6 +107,15 @@ #define MICROPY_ALLOC_GC_STACK_SIZE (64) #endif +// Be conservative and always clear to zero newly (re)allocated memory in the GC. +// This helps eliminate stray pointers that hold on to memory that's no longer +// used. It decreases performance due to unnecessary memory clearing. +// TODO Do analysis to understand why some memory is not properly cleared and +// find a more efficient way to clear it. +#ifndef MICROPY_GC_CONSERVATIVE_CLEAR +#define MICROPY_GC_CONSERVATIVE_CLEAR (1) +#endif + // Support automatic GC when reaching allocation threshold, // configurable by gc.threshold(). #ifndef MICROPY_GC_ALLOC_THRESHOLD @@ -887,6 +896,11 @@ typedef double mp_float_t; #define MICROPY_PY_UBINASCII (0) #endif +// Depends on MICROPY_PY_UZLIB +#ifndef MICROPY_PY_UBINASCII_CRC32 +#define MICROPY_PY_UBINASCII_CRC32 (0) +#endif + #ifndef MICROPY_PY_URANDOM #define MICROPY_PY_URANDOM (0) #endif @@ -909,6 +923,10 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_I2C (0) #endif +#ifndef MICROPY_PY_MACHINE_SPI +#define MICROPY_PY_MACHINE_SPI (0) +#endif + #ifndef MICROPY_PY_USSL #define MICROPY_PY_USSL (0) #endif diff --git a/py/mpprint.c b/py/mpprint.c index cb49b1227a..97ea33ad2a 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -537,10 +537,12 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); break; } - // fall through to default case to print unknown format char + assert(!"unsupported fmt char"); } #endif default: + // if it's not %% then it's an unsupported format character + assert(*fmt == '%' || !"unsupported fmt char"); print->print_strn(print->data, fmt, 1); chrs += 1; break; diff --git a/py/objfun.c b/py/objfun.c index 293d06427d..3fd25fb224 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -165,7 +165,7 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) { #define VM_DETECT_STACK_OVERFLOW (0) #if MICROPY_STACKLESS -mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); @@ -178,8 +178,8 @@ mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, // allocate state for locals and stack size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); - mp_code_state *code_state; - code_state = m_new_obj_var_maybe(mp_code_state, byte, state_size); + mp_code_state_t *code_state; + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; } @@ -220,12 +220,12 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const // allocate state for locals and stack mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); - mp_code_state *code_state = NULL; + mp_code_state_t *code_state = NULL; if (state_size > VM_MAX_STATE_ON_STACK) { - code_state = m_new_obj_var_maybe(mp_code_state, byte, state_size); + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } if (code_state == NULL) { - code_state = alloca(sizeof(mp_code_state) + state_size); + code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } @@ -287,7 +287,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const // free the state if it was allocated on the heap if (state_size != 0) { - m_del_var(mp_code_state, byte, state_size, code_state); + m_del_var(mp_code_state_t, byte, state_size, code_state); } if (vm_return_kind == MP_VM_RETURN_NORMAL) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 99d9445377..8c32a36496 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -46,7 +46,7 @@ typedef struct _mp_obj_gen_wrap_t { typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; mp_obj_dict_t *globals; - mp_code_state code_state; + mp_code_state_t code_state; } mp_obj_gen_instance_t; STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/py/objstr.c b/py/objstr.c index e83ff7c844..406ccf290a 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -158,6 +158,9 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; @@ -191,6 +194,9 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; diff --git a/py/objstr.h b/py/objstr.h index 07929156cb..e14568dac4 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -39,6 +39,7 @@ typedef struct _mp_obj_str_t { #define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str} // use this macro to extract the string hash +// warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data #define GET_STR_HASH(str_obj_in, str_hash) \ mp_uint_t str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->hash; } diff --git a/py/py.mk b/py/py.mk index a110c9f608..abea7215b2 100644 --- a/py/py.mk +++ b/py/py.mk @@ -208,6 +208,7 @@ PY_O_BASENAME = \ ../extmod/machine_pinbase.o \ ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ + ../extmod/machine_spi.o \ ../extmod/modussl_axtls.o \ ../extmod/modurandom.o \ ../extmod/modwebsocket.o \ diff --git a/py/runtime.c b/py/runtime.c index 04b3a34de4..48e815f0fa 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -217,6 +217,10 @@ mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { // fast path for hashing str/bytes GET_STR_HASH(arg, h); + if (h == 0) { + GET_STR_DATA_LEN(arg, data, len); + h = qstr_compute_hash(data, len); + } return MP_OBJ_NEW_SMALL_INT(h); } else { mp_obj_type_t *type = mp_obj_get_type(arg); diff --git a/py/vm.c b/py/vm.c index 65801401d1..f9bdedff88 100644 --- a/py/vm.c +++ b/py/vm.c @@ -127,7 +127,7 @@ typedef enum { // MP_VM_RETURN_NORMAL, sp valid, return value in *sp // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in fastn[0] -mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc) { +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { #define SELECTIVE_EXC_IP (0) #if SELECTIVE_EXC_IP #define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */ @@ -904,7 +904,7 @@ unwind_jump:; code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -940,7 +940,7 @@ unwind_jump:; mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { @@ -976,7 +976,7 @@ unwind_jump:; mp_uint_t n_kw = (unum >> 8) & 0xff; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -1011,7 +1011,7 @@ unwind_jump:; mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { diff --git a/stmhal/Makefile b/stmhal/Makefile index 1ad2783fca..2c6ea806eb 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -284,7 +284,7 @@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY diff --git a/stmhal/adc.c b/stmhal/adc.c index 39f0364078..bcf8956254 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -54,7 +54,16 @@ #define ADCx (ADC1) #define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#define ADC_NUM_GPIO_CHANNELS (16) + +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#elif defined(MCU_SERIES_L4) +#define ADC_FIRST_GPIO_CHANNEL (1) +#define ADC_LAST_GPIO_CHANNEL (16) +#else +#error Unsupported processor +#endif #if defined(STM32F405xx) || defined(STM32F415xx) || \ defined(STM32F407xx) || defined(STM32F417xx) || \ @@ -124,7 +133,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { return; } - if (adc_obj->channel < ADC_NUM_GPIO_CHANNELS) { + if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) { // Channels 0-16 correspond to real pins. Configure the GPIO pin in // ADC mode. const pin_obj_t *pin = pin_adc1[adc_obj->channel]; @@ -253,8 +262,14 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin if (!is_adcx_channel(channel)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel)); } - if (pin_adc1[channel] == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "channel %d not available on this board", channel)); + + + if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) { + // these channels correspond to physical GPIO ports so make sure they exist + if (pin_adc1[channel] == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "channel %d not available on this board", channel)); + } } pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); @@ -423,7 +438,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution) { "resolution %d not supported", resolution)); } - for (uint32_t channel = 0; channel < ADC_NUM_GPIO_CHANNELS; channel++) { + for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) { // Channels 0-16 correspond to real pins. Configure the GPIO pin in // ADC mode. const pin_obj_t *pin = pin_adc1[channel]; diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py index b7f4842144..ae614877d5 100755 --- a/stmhal/boards/make-pins.py +++ b/stmhal/boards/make-pins.py @@ -303,7 +303,9 @@ class Pins(object): def print_adc(self, adc_num): print(''); print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) - for channel in range(16): + for channel in range(17): + if channel == 16: + print('#if defined(MCU_SERIES_L4)') adc_found = False for named_pin in self.cpu_pins: pin = named_pin.pin() @@ -314,6 +316,8 @@ class Pins(object): break if not adc_found: print(' NULL, // {:d}'.format(channel)) + if channel == 16: + print('#endif') print('};') diff --git a/stmhal/main.c b/stmhal/main.c index 30dddaf989..32baae5320 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -137,8 +137,8 @@ static const char fresh_boot_py[] = "import machine\r\n" "import pyb\r\n" "#pyb.main('main.py') # main script to run after this one\r\n" -"#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device\r\n" -"#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse\r\n" +"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n" +"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n" ; static const char fresh_main_py[] = diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c index fbd1196446..c0e30ce050 100644 --- a/stmhal/modusocket.c +++ b/stmhal/modusocket.c @@ -83,6 +83,7 @@ STATIC mp_obj_t socket_close(mp_obj_t self_in) { mod_network_socket_obj_t *self = self_in; if (self->nic != MP_OBJ_NULL) { self->nic_type->close(self); + self->nic = MP_OBJ_NULL; } return mp_const_none; } diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 3122a90655..98d1e17e3d 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -93,6 +93,7 @@ #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) diff --git a/stmhal/pin.c b/stmhal/pin.c index e3ae0be400..9bd4e7a6d9 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -199,15 +199,15 @@ STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t if (mode == GPIO_MODE_INPUT) { mode_qst = MP_QSTR_IN; } else if (mode == GPIO_MODE_OUTPUT_PP) { - mode_qst = MP_QSTR_OUT_PP; + mode_qst = MP_QSTR_OUT; } else if (mode == GPIO_MODE_OUTPUT_OD) { - mode_qst = MP_QSTR_OUT_OD; + mode_qst = MP_QSTR_OPEN_DRAIN; } else { af = true; if (mode == GPIO_MODE_AF_PP) { - mode_qst = MP_QSTR_AF_PP; + mode_qst = MP_QSTR_ALT; } else { - mode_qst = MP_QSTR_AF_OD; + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; } } mp_print_str(print, qstr_str(mode_qst)); diff --git a/stmhal/spi.c b/stmhal/spi.c index fbc5f9aa48..85f1709200 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -30,6 +30,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" #include "irq.h" #include "pin.h" #include "genhdr/pins.h" @@ -327,6 +328,90 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t return HAL_OK; } +STATIC void spi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf, uint32_t timeout) { + // Note: there seems to be a problem sending 1 byte using DMA the first + // time directly after the SPI/DMA is initialised. The cause of this is + // unknown but we sidestep the issue by using polling for 1 byte transfer. + + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; + HAL_StatusTypeDef status; + + if (dest_len == 0) { + // send only + if (src_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Transmit(self->spi, (uint8_t*)src_buf, src_len, timeout); + } else { + DMA_HandleTypeDef tx_dma; + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + self->spi->hdmarx = NULL; + status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src_buf, src_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + dma_deinit(self->tx_dma_descr); + } + } else if (src_len == 0) { + // receive only + if (dest_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Receive(self->spi, dest_buf, dest_len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + if (self->spi->Init.Mode == SPI_MODE_MASTER) { + // in master mode the HAL actually does a TransmitReceive call + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + } else { + self->spi->hdmatx = NULL; + } + dma_init(&rx_dma, self->rx_dma_descr, self->spi); + self->spi->hdmarx = &rx_dma; + + status = HAL_SPI_Receive_DMA(self->spi, dest_buf, dest_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + if (self->spi->hdmatx != NULL) { + dma_deinit(self->tx_dma_descr); + } + dma_deinit(self->rx_dma_descr); + } + } else { + // send and receive + // requires src_len==dest_len + if (src_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_TransmitReceive(self->spi, (uint8_t*)src_buf, dest_buf, src_len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + dma_init(&rx_dma, self->rx_dma_descr, self->spi); + self->spi->hdmarx = &rx_dma; + status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src_buf, dest_buf, src_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + dma_deinit(self->tx_dma_descr); + dma_deinit(self->rx_dma_descr); + } + } + + if (status != HAL_OK) { + mp_hal_raise(status); + } +} + +STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + if (src_len == 1 && dest_len > 1) { + // this catches read and readinto + // copy the single output byte to the dest buffer and use that as source + memset(dest_buf, src_buf[0], dest_len); + src_len = dest_len; + src_buf = dest_buf; + } + spi_transfer(self_in, src_len, src_buf, dest_len, dest_buf, 100); +} + /******************************************************************************/ /* Micro Python bindings */ @@ -556,27 +641,7 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); // send the data - // Note: there seems to be a problem sending 1 byte using DMA the first - // time directly after the SPI/DMA is initialised. The cause of this is - // unknown but we sidestep the issue by using polling for 1 byte transfer. - HAL_StatusTypeDef status; - if (bufinfo.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, args[1].u_int); - } else { - DMA_HandleTypeDef tx_dma; - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - self->spi->hdmarx = NULL; - status = HAL_SPI_Transmit_DMA(self->spi, bufinfo.buf, bufinfo.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[1].u_int); - } - dma_deinit(self->tx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + spi_transfer((mp_obj_base_t*)self, bufinfo.len, bufinfo.buf, 0, NULL, args[1].u_int); return mp_const_none; } @@ -610,34 +675,7 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); // receive the data - HAL_StatusTypeDef status; - if (vstr.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_Receive(self->spi, (uint8_t*)vstr.buf, vstr.len, args[1].u_int); - } else { - DMA_HandleTypeDef tx_dma, rx_dma; - if (self->spi->Init.Mode == SPI_MODE_MASTER) { - // in master mode the HAL actually does a TransmitReceive call - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - } else { - self->spi->hdmatx = NULL; - } - dma_init(&rx_dma, self->rx_dma_descr, self->spi); - self->spi->hdmarx = &rx_dma; - - status = HAL_SPI_Receive_DMA(self->spi, (uint8_t*)vstr.buf, vstr.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[1].u_int); - } - if (self->spi->hdmatx != NULL) { - dma_deinit(self->tx_dma_descr); - } - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + spi_transfer((mp_obj_base_t*)self, 0, NULL, vstr.len, (uint8_t*)vstr.buf, args[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -706,27 +744,8 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp } } - // send and receive the data - HAL_StatusTypeDef status; - if (bufinfo_send.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, args[2].u_int); - } else { - DMA_HandleTypeDef tx_dma, rx_dma; - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - dma_init(&rx_dma, self->rx_dma_descr, self->spi); - self->spi->hdmarx = &rx_dma; - status = HAL_SPI_TransmitReceive_DMA(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[2].u_int); - } - dma_deinit(self->tx_dma_descr); - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + // do the transfer + spi_transfer((mp_obj_base_t*)self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.len, bufinfo_recv.buf, args[2].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -741,6 +760,13 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { // instance methods { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_spi_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_spi_deinit_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_machine_spi_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_machine_spi_readinto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_machine_spi_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)&mp_machine_spi_write_readinto_obj }, + + // legacy methods { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_spi_send_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_spi_recv_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj }, @@ -766,10 +792,15 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_spi_p = { + .transfer = spi_transfer_machine, +}; + const mp_obj_type_t pyb_spi_type = { { &mp_type_type }, .name = MP_QSTR_SPI, .print = pyb_spi_print, .make_new = pyb_spi_make_new, + .protocol = &pyb_spi_p, .locals_dict = (mp_obj_t)&pyb_spi_locals_dict, }; diff --git a/tests/cmdline/cmd_optimise.py b/tests/cmdline/cmd_optimise.py new file mode 100644 index 0000000000..79d3bb44fd --- /dev/null +++ b/tests/cmdline/cmd_optimise.py @@ -0,0 +1,4 @@ +# cmdline: -O +# test optimisation output +print(__debug__) +assert 0 diff --git a/tests/cmdline/cmd_optimise.py.exp b/tests/cmdline/cmd_optimise.py.exp new file mode 100644 index 0000000000..bc59c12aa1 --- /dev/null +++ b/tests/cmdline/cmd_optimise.py.exp @@ -0,0 +1 @@ +False diff --git a/tests/extmod/ubinascii_crc32.py b/tests/extmod/ubinascii_crc32.py new file mode 100644 index 0000000000..2c40177518 --- /dev/null +++ b/tests/extmod/ubinascii_crc32.py @@ -0,0 +1,20 @@ +try: + import ubinascii as binascii +except ImportError: + import binascii +try: + binascii.crc32 +except AttributeError: + print("SKIP") + import sys + sys.exit() + +print(hex(binascii.crc32(b'The quick brown fox jumps over the lazy dog'))) +print(hex(binascii.crc32(b'\x00' * 32))) +print(hex(binascii.crc32(b'\xff' * 32))) +print(hex(binascii.crc32(bytes(range(32))))) + +print(hex(binascii.crc32(b' over the lazy dog', binascii.crc32(b'The quick brown fox jumps')))) +print(hex(binascii.crc32(b'\x00' * 16, binascii.crc32(b'\x00' * 16)))) +print(hex(binascii.crc32(b'\xff' * 16, binascii.crc32(b'\xff' * 16)))) +print(hex(binascii.crc32(bytes(range(16, 32)), binascii.crc32(bytes(range(16)))))) diff --git a/tests/extmod/uzlib_decompio.py b/tests/extmod/uzlib_decompio.py new file mode 100644 index 0000000000..ee3204d07c --- /dev/null +++ b/tests/extmod/uzlib_decompio.py @@ -0,0 +1,19 @@ +try: + import zlib +except ImportError: + import uzlib as zlib +import uio as io + + +# Raw DEFLATE bitstream +buf = io.BytesIO(b'\xcbH\xcd\xc9\xc9\x07\x00') +inp = zlib.DecompIO(buf) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(buf.seek(0, 1)) +print(inp.read(2)) +print(inp.read()) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(inp.read()) +print(buf.seek(0, 1)) diff --git a/tests/extmod/uzlib_decompio.py.exp b/tests/extmod/uzlib_decompio.py.exp new file mode 100644 index 0000000000..6ef811d7db --- /dev/null +++ b/tests/extmod/uzlib_decompio.py.exp @@ -0,0 +1,9 @@ +0 +b'h' +2 +b'el' +b'lo' +7 +b'' +b'' +7 diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 7860d68124..57c8eeba89 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -1,5 +1,6 @@ import sys import uos +import uerrno try: uos.VfsFat except AttributeError: @@ -84,3 +85,15 @@ assert vfs.listdir() == ["sub_file.txt"] vfs.chdir("..") print("getcwd:", vfs.getcwd()) + + +vfs.umount() +try: + vfs.listdir() +except OSError as e: + assert e.args[0] == uerrno.ENODEV +else: + raise AssertionError("expected OSError not thrown") + +vfs = uos.VfsFat(bdev, "/ramdisk") +assert vfs.listdir() == ['foo_dir', 'moved-to-root.txt'] diff --git a/tests/run-tests b/tests/run-tests index f796f28630..5e8819729e 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -200,7 +200,9 @@ def run_tests(pyb, tests, args): # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': skip_tests.add('basics/memoryerror.py') + skip_tests.add('thread/thread_gc1.py') # has reliability issues skip_tests.add('thread/thread_lock4.py') # has reliability issues + skip_tests.add('thread/stress_heap.py') # has reliability issues if not has_complex: skip_tests.add('float/complex1.py') diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 8f330f1da2..72bcc9994a 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -5,4 +5,11 @@ except NameError: import sys sys.exit() -extra_coverage() +data = extra_coverage() + +# test hashing of str/bytes that have an invalid hash +print(data) +print(hash(data[0])) +print(hash(data[1])) +print(hash(bytes(data[0], 'utf8'))) +print(hash(str(data[1], 'utf8'))) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index db282b152c..ea73a54e4c 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -7,7 +7,6 @@ ab abc false true (null) -t -2147483648 2147483648 80000000 @@ -36,3 +35,8 @@ ementation 12345678 0 0 +('0123456789', b'0123456789') +7300 +7300 +7300 +7300 diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index a7c3d8f918..bc8ac4fbd3 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -283,15 +283,15 @@ class RawCode: # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) - if is_str_type(obj): - obj = bytes_cons(obj, 'utf8') - print('STATIC const mp_obj_str_t %s = ' - '{{&mp_type_str}, 0, %u, (const byte*)"%s"};' - % (obj_name, len(obj), ''.join(('\\x%02x' % b) for b in obj))) - elif is_bytes_type(obj): - print('STATIC const mp_obj_str_t %s = ' - '{{&mp_type_bytes}, 0, %u, (const byte*)"%s"};' - % (obj_name, len(obj), ''.join(('\\x%02x' % b) for b in obj))) + if is_str_type(obj) or is_bytes_type(obj): + if is_str_type(obj): + obj = bytes_cons(obj, 'utf8') + obj_type = 'mp_type_str' + else: + obj_type = 'mp_type_bytes' + print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' + % (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), + len(obj), ''.join(('\\x%02x' % b) for b in obj))) elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int @@ -320,6 +320,9 @@ class RawCode: print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) print('#endif') + elif type(obj) is complex: + print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' + % (obj_name, obj.real, obj.imag)) else: # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) @@ -444,10 +447,7 @@ def dump_mpy(raw_codes): for rc in raw_codes: rc.dump() -def freeze_mpy(qcfgs, base_qstrs, raw_codes): - cfg_bytes_len = int(qcfgs['BYTES_IN_LEN']) - cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH']) - +def freeze_mpy(base_qstrs, raw_codes): # add to qstrs new = {} for q in global_qstrs: @@ -488,6 +488,15 @@ def freeze_mpy(qcfgs, base_qstrs, raw_codes): print('#endif') print() + print('#if MICROPY_PY_BUILTINS_COMPLEX') + print('typedef struct _mp_obj_complex_t {') + print(' mp_obj_base_t base;') + print(' mp_float_t real;') + print(' mp_float_t imag;') + print('} mp_obj_complex_t;') + print('#endif') + print() + print('enum {') for i in range(len(new)): if i == 0: @@ -505,7 +514,8 @@ def freeze_mpy(qcfgs, base_qstrs, raw_codes): print(' %u, // used entries' % len(new)) print(' {') for _, _, qstr in new: - print(' %s,' % qstrutil.make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)) + print(' %s,' + % qstrutil.make_bytes(config.MICROPY_QSTR_BYTES_IN_LEN, config.MICROPY_QSTR_BYTES_IN_HASH, qstr)) print(' },') print('};') @@ -549,10 +559,15 @@ def main(): }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size + # set config values for qstrs, and get the existing base set of qstrs if args.qstr_header: qcfgs, base_qstrs = qstrutil.parse_input_headers([args.qstr_header]) + config.MICROPY_QSTR_BYTES_IN_LEN = int(qcfgs['BYTES_IN_LEN']) + config.MICROPY_QSTR_BYTES_IN_HASH = int(qcfgs['BYTES_IN_HASH']) else: - qcfgs, base_qstrs = {'BYTES_IN_LEN':1, 'BYTES_IN_HASH':1}, {} + config.MICROPY_QSTR_BYTES_IN_LEN = 1 + config.MICROPY_QSTR_BYTES_IN_HASH = 1 + base_qstrs = {} raw_codes = [read_mpy(file) for file in args.files] @@ -560,7 +575,7 @@ def main(): dump_mpy(raw_codes) elif args.freeze: try: - freeze_mpy(qcfgs, base_qstrs, raw_codes) + freeze_mpy(base_qstrs, raw_codes) except FreezeError as er: print(er, file=sys.stderr) sys.exit(1) diff --git a/unix/Makefile b/unix/Makefile index cb9a999f08..3afa80dfa8 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -183,7 +183,7 @@ ifneq ($(FROZEN_MPY_DIR),) # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY diff --git a/unix/coverage.c b/unix/coverage.c index 9d53725543..c84a653f75 100644 --- a/unix/coverage.c +++ b/unix/coverage.c @@ -1,18 +1,22 @@ #include #include "py/obj.h" +#include "py/objstr.h" #include "py/runtime.h" #include "py/repl.h" #include "py/mpz.h" #if defined(MICROPY_UNIX_COVERAGE) +// str/bytes objects without a valid hash +STATIC const mp_obj_str_t str_no_hash_obj = {{&mp_type_str}, 0, 10, (const byte*)"0123456789"}; +STATIC const mp_obj_str_t bytes_no_hash_obj = {{&mp_type_bytes}, 0, 10, (const byte*)"0123456789"}; + // function to run extra tests for things that can't be checked by scripts STATIC mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) { mp_printf(&mp_plat_print, "# mp_printf\n"); - mp_printf(&mp_plat_print, "%"); // nothing after percent mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding mp_printf(&mp_plat_print, "%ld\n", 123); // long @@ -21,7 +25,6 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools mp_printf(&mp_plat_print, "%s\n", NULL); // null string - mp_printf(&mp_plat_print, "%t\n"); // non-format char mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned @@ -111,7 +114,9 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); } - return mp_const_none; + // return a tuple of data for testing on the Python side + mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj}; + return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items); } MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage); diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 9845e1ce5f..56cfaa2ac1 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -117,6 +117,7 @@ #define MICROPY_PY_UHASHLIB_SHA1 (1) #endif #define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_URANDOM (1) #ifndef MICROPY_PY_USELECT #define MICROPY_PY_USELECT (1)