micropython: add micropython component

This commit is contained in:
KY-zhang-X
2022-09-29 12:10:37 +08:00
parent 1514f1cb9b
commit dd76146324
2679 changed files with 354110 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
This is a SDdatalogger, to log data from the accelerometer to the SD-card. It also functions as card reader, so you can easily get the data on your PC.
To run, put the boot.py, cardreader.py and datalogger.py files on either the flash or the SD-card of your pyboard.
Upon reset, the datalogger script is run and logs the data. If you press the user button after reset and hold it until the orange LED goes out, you enter the cardreader mode and the filesystem is mounted to your PC.

View File

@@ -0,0 +1,25 @@
# boot.py -- runs on boot-up
# Let's you choose which script to run.
# > To run 'datalogger.py':
# * press reset and do nothing else
# > To run 'cardreader.py':
# * press reset
# * press user switch and hold until orange LED goes out
import pyb
pyb.LED(3).on() # indicate we are waiting for switch press
pyb.delay(2000) # wait for user to maybe press the switch
switch_value = pyb.Switch()() # sample the switch at end of delay
pyb.LED(3).off() # indicate that we finished waiting for the switch
pyb.LED(4).on() # indicate that we are selecting the mode
if switch_value:
pyb.usb_mode("VCP+MSC")
pyb.main("cardreader.py") # if switch was pressed, run this
else:
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

View File

@@ -0,0 +1,2 @@
# cardread.py
# This is called when the user enters cardreader mode. It does nothing.

View File

@@ -0,0 +1,33 @@
# datalogger.py
# Logs the data from the acceleromter to a file on the SD-card
import pyb
# creating objects
accel = pyb.Accel()
blue = pyb.LED(4)
switch = pyb.Switch()
# loop
while True:
# wait for interrupt
# this reduces power consumption while waiting for switch press
pyb.wfi()
# start if switch is pressed
if switch():
pyb.delay(200) # delay avoids detection of multiple presses
blue.on() # blue LED indicates file open
log = open("/sd/log.csv", "w") # open file on SD (SD: '/sd/', flash: '/flash/)
# until switch is pressed again
while not switch():
t = pyb.millis() # get time
x, y, z = accel.filtered_xyz() # get acceleration data
log.write("{},{},{},{}\n".format(t, x, y, z)) # write data to file
# end after switch is pressed again
log.close() # close file
blue.off() # blue LED indicates file closed
pyb.delay(200) # delay avoids detection of multiple presses

View File

@@ -0,0 +1,34 @@
# This is an example on how to access accelerometer on
# PyBoard directly using I2C bus. As such, it's more
# intended to be an I2C example, rather than accelerometer
# example. For the latter, using pyb.Accel class is
# much easier.
from machine import Pin
from machine import I2C
import time
# Accelerometer needs to be powered on first. Even
# though signal is called "AVDD", and there's separate
# "DVDD", without AVDD, it won't event talk on I2C bus.
accel_pwr = Pin("MMA_AVDD")
accel_pwr.value(1)
i2c = I2C(1, baudrate=100000)
addrs = i2c.scan()
print("Scanning devices:", [hex(x) for x in addrs])
if 0x4C not in addrs:
print("Accelerometer is not detected")
ACCEL_ADDR = 0x4C
ACCEL_AXIS_X_REG = 0
ACCEL_MODE_REG = 7
# Now activate measurements
i2c.mem_write(b"\x01", ACCEL_ADDR, ACCEL_MODE_REG)
print("Try to move accelerometer and watch the values")
while True:
val = i2c.mem_read(1, ACCEL_ADDR, ACCEL_AXIS_X_REG)
print(val[0])
time.sleep(1)

View File

@@ -0,0 +1,20 @@
# log the accelerometer values to a .csv-file on the SD-card
import pyb
accel = pyb.Accel() # create object of accelerometer
blue = pyb.LED(4) # create object of blue LED
# open file to write data - /sd/ is the SD-card, /flash/ the internal memory
log = open("/sd/log.csv", "w")
blue.on() # turn on blue LED
# do 100 times (if the board is connected via USB, you can't write longer because the PC tries to open the filesystem which messes up your file.)
for i in range(100):
t = pyb.millis() # get time since reset
x, y, z = accel.filtered_xyz() # get acceleration data
log.write("{},{},{},{}\n".format(t, x, y, z)) # write data to file
log.close() # close file
blue.off() # turn off LED

View File

@@ -0,0 +1,87 @@
# flash LED #1 using inline assembler
# this version is overly verbose and uses word stores
@micropython.asm_thumb
def flash_led(r0):
movw(r1, (stm.GPIOA + stm.GPIO_BSRRL) & 0xFFFF)
movt(r1, ((stm.GPIOA + stm.GPIO_BSRRL) >> 16) & 0x7FFF)
movw(r2, 1 << 13)
movt(r2, 0)
movw(r3, 0)
movt(r3, 1 << 13)
b(loop_entry)
label(loop1)
# turn LED on
str(r2, [r1, 0])
# delay for a bit
movw(r4, 5599900 & 0xFFFF)
movt(r4, (5599900 >> 16) & 0xFFFF)
label(delay_on)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_on)
# turn LED off
str(r3, [r1, 0])
# delay for a bit
movw(r4, 5599900 & 0xFFFF)
movt(r4, (5599900 >> 16) & 0xFFFF)
label(delay_off)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_off)
# loop r0 times
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)
# flash LED #2 using inline assembler
# this version uses half-word sortes, and the convenience assembler operation 'movwt'
@micropython.asm_thumb
def flash_led_v2(r0):
# get the GPIOA address in r1
movwt(r1, stm.GPIOA)
# get the bit mask for PA14 (the pin LED #2 is on)
movw(r2, 1 << 14)
b(loop_entry)
label(loop1)
# turn LED on
strh(r2, [r1, stm.GPIO_BSRRL])
# delay for a bit
movwt(r4, 5599900)
label(delay_on)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_on)
# turn LED off
strh(r2, [r1, stm.GPIO_BSRRH])
# delay for a bit
movwt(r4, 5599900)
label(delay_off)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_off)
# loop r0 times
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)
flash_led(5)
flash_led_v2(5)

View File

@@ -0,0 +1,59 @@
@micropython.asm_thumb
def asm_sum_words(r0, r1):
# r0 = len
# r1 = ptr
# r2 = sum
# r3 = dummy
mov(r2, 0)
b(loop_entry)
label(loop1)
ldr(r3, [r1, 0])
add(r2, r2, r3)
add(r1, r1, 4)
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)
mov(r0, r2)
@micropython.asm_thumb
def asm_sum_bytes(r0, r1):
# r0 = len
# r1 = ptr
# r2 = sum
# r3 = dummy
mov(r2, 0)
b(loop_entry)
label(loop1)
ldrb(r3, [r1, 0])
add(r2, r2, r3)
add(r1, r1, 1)
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)
mov(r0, r2)
import array
b = array.array("l", (100, 200, 300, 400))
n = asm_sum_words(len(b), b)
print(b, n)
b = array.array("b", (10, 20, 30, 40, 50, 60, 70, 80))
n = asm_sum_bytes(len(b), b)
print(b, n)

View File

@@ -0,0 +1,93 @@
# Helpers for generating BLE advertising payloads.
from micropython import const
import struct
import bluetooth
# Advertising payloads are repeated packets of the following form:
# 1 byte data length (N + 1)
# 1 byte type (see constants below)
# N bytes type-specific data
_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)
# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
payload = bytearray()
def _append(adv_type, value):
nonlocal payload
payload += struct.pack("BB", len(value) + 1, adv_type) + value
_append(
_ADV_TYPE_FLAGS,
struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
)
if name:
_append(_ADV_TYPE_NAME, name)
if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(_ADV_TYPE_UUID16_COMPLETE, b)
elif len(b) == 4:
_append(_ADV_TYPE_UUID32_COMPLETE, b)
elif len(b) == 16:
_append(_ADV_TYPE_UUID128_COMPLETE, b)
# See org.bluetooth.characteristic.gap.appearance.xml
if appearance:
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
return payload
def decode_field(payload, adv_type):
i = 0
result = []
while i + 1 < len(payload):
if payload[i + 1] == adv_type:
result.append(payload[i + 2 : i + payload[i] + 1])
i += 1 + payload[i]
return result
def decode_name(payload):
n = decode_field(payload, _ADV_TYPE_NAME)
return str(n[0], "utf-8") if n else ""
def decode_services(payload):
services = []
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
services.append(bluetooth.UUID(u))
return services
def demo():
payload = advertising_payload(
name="micropython",
services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
)
print(payload)
print(decode_name(payload))
print(decode_services(payload))
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,194 @@
# This example demonstrates a simple temperature sensor peripheral.
#
# The sensor's local value updates every second, and it will notify
# any connected central every 10 seconds.
#
# Work-in-progress demo of implementing bonding and passkey auth.
import bluetooth
import random
import struct
import time
import json
import binascii
from ble_advertising import advertising_payload
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_INDICATE_DONE = const(20)
_IRQ_ENCRYPTION_UPDATE = const(28)
_IRQ_PASSKEY_ACTION = const(31)
_IRQ_GET_SECRET = const(29)
_IRQ_SET_SECRET = const(30)
_FLAG_READ = const(0x0002)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
_FLAG_READ_ENCRYPTED = const(0x0200)
# org.bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
# org.bluetooth.characteristic.temperature
_TEMP_CHAR = (
bluetooth.UUID(0x2A6E),
_FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE | _FLAG_READ_ENCRYPTED,
)
_ENV_SENSE_SERVICE = (
_ENV_SENSE_UUID,
(_TEMP_CHAR,),
)
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
_IO_CAPABILITY_DISPLAY_ONLY = const(0)
_IO_CAPABILITY_DISPLAY_YESNO = const(1)
_IO_CAPABILITY_KEYBOARD_ONLY = const(2)
_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)
_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)
_PASSKEY_ACTION_INPUT = const(2)
_PASSKEY_ACTION_DISP = const(3)
_PASSKEY_ACTION_NUMCMP = const(4)
class BLETemperature:
def __init__(self, ble, name="mpy-temp"):
self._ble = ble
self._load_secrets()
self._ble.irq(self._irq)
self._ble.config(bond=True)
self._ble.config(le_secure=True)
self._ble.config(mitm=True)
self._ble.config(io=_IO_CAPABILITY_DISPLAY_YESNO)
self._ble.active(True)
self._ble.config(addr_mode=2)
((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
self._connections = set()
self._payload = advertising_payload(
name=name, services=[_ENV_SENSE_UUID], appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER
)
self._advertise()
def _irq(self, event, data):
# Track connections so we can send notifications.
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
self._connections.remove(conn_handle)
self._save_secrets()
# Start advertising again to allow a new connection.
self._advertise()
elif event == _IRQ_ENCRYPTION_UPDATE:
conn_handle, encrypted, authenticated, bonded, key_size = data
print("encryption update", conn_handle, encrypted, authenticated, bonded, key_size)
elif event == _IRQ_PASSKEY_ACTION:
conn_handle, action, passkey = data
print("passkey action", conn_handle, action, passkey)
if action == _PASSKEY_ACTION_NUMCMP:
accept = int(input("accept? "))
self._ble.gap_passkey(conn_handle, action, accept)
elif action == _PASSKEY_ACTION_DISP:
print("displaying 123456")
self._ble.gap_passkey(conn_handle, action, 123456)
elif action == _PASSKEY_ACTION_INPUT:
print("prompting for passkey")
passkey = int(input("passkey? "))
self._ble.gap_passkey(conn_handle, action, passkey)
else:
print("unknown action")
elif event == _IRQ_GATTS_INDICATE_DONE:
conn_handle, value_handle, status = data
elif event == _IRQ_SET_SECRET:
sec_type, key, value = data
key = sec_type, bytes(key)
value = bytes(value) if value else None
print("set secret:", key, value)
if value is None:
if key in self._secrets:
del self._secrets[key]
return True
else:
return False
else:
self._secrets[key] = value
return True
elif event == _IRQ_GET_SECRET:
sec_type, index, key = data
print("get secret:", sec_type, index, bytes(key) if key else None)
if key is None:
i = 0
for (t, _key), value in self._secrets.items():
if t == sec_type:
if i == index:
return value
i += 1
return None
else:
key = sec_type, bytes(key)
return self._secrets.get(key, None)
def set_temperature(self, temp_deg_c, notify=False, indicate=False):
# Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
# Write the local value, ready for a central to read.
self._ble.gatts_write(self._handle, struct.pack("<h", int(temp_deg_c * 100)))
if notify or indicate:
for conn_handle in self._connections:
if notify:
# Notify connected centrals.
self._ble.gatts_notify(conn_handle, self._handle)
if indicate:
# Indicate connected centrals.
self._ble.gatts_indicate(conn_handle, self._handle)
def _advertise(self, interval_us=500000):
self._ble.config(addr_mode=2)
self._ble.gap_advertise(interval_us, adv_data=self._payload)
def _load_secrets(self):
self._secrets = {}
try:
with open("secrets.json", "r") as f:
entries = json.load(f)
for sec_type, key, value in entries:
self._secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value)
except:
print("no secrets available")
def _save_secrets(self):
try:
with open("secrets.json", "w") as f:
json_secrets = [
(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value))
for (sec_type, key), value in self._secrets.items()
]
json.dump(json_secrets, f)
except:
print("failed to save secrets")
def demo():
ble = bluetooth.BLE()
temp = BLETemperature(ble)
t = 25
i = 0
while True:
# Write every second, notify every 10 seconds.
i = (i + 1) % 10
temp.set_temperature(t, notify=i == 0, indicate=False)
# Random walk the temperature.
t += random.uniform(-0.5, 0.5)
time.sleep_ms(1000)
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,245 @@
# This example finds and connects to a peripheral running the
# UART service (e.g. ble_simple_peripheral.py).
import bluetooth
import random
import struct
import time
import micropython
from ble_advertising import decode_services, decode_name
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_IRQ_GATTS_READ_REQUEST = const(4)
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
_IRQ_PERIPHERAL_CONNECT = const(7)
_IRQ_PERIPHERAL_DISCONNECT = const(8)
_IRQ_GATTC_SERVICE_RESULT = const(9)
_IRQ_GATTC_SERVICE_DONE = const(10)
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
_IRQ_GATTC_READ_RESULT = const(15)
_IRQ_GATTC_READ_DONE = const(16)
_IRQ_GATTC_WRITE_DONE = const(17)
_IRQ_GATTC_NOTIFY = const(18)
_IRQ_GATTC_INDICATE = const(19)
_ADV_IND = const(0x00)
_ADV_DIRECT_IND = const(0x01)
_ADV_SCAN_IND = const(0x02)
_ADV_NONCONN_IND = const(0x03)
_UART_SERVICE_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_RX_CHAR_UUID = bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_TX_CHAR_UUID = bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
class BLESimpleCentral:
def __init__(self, ble):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
self._reset()
def _reset(self):
# Cached name and address from a successful scan.
self._name = None
self._addr_type = None
self._addr = None
# Callbacks for completion of various operations.
# These reset back to None after being invoked.
self._scan_callback = None
self._conn_callback = None
self._read_callback = None
# Persistent callback for when new data is notified from the device.
self._notify_callback = None
# Connected device.
self._conn_handle = None
self._start_handle = None
self._end_handle = None
self._tx_handle = None
self._rx_handle = None
def _irq(self, event, data):
if event == _IRQ_SCAN_RESULT:
addr_type, addr, adv_type, rssi, adv_data = data
if adv_type in (_ADV_IND, _ADV_DIRECT_IND) and _UART_SERVICE_UUID in decode_services(
adv_data
):
# Found a potential device, remember it and stop scanning.
self._addr_type = addr_type
self._addr = bytes(
addr
) # Note: addr buffer is owned by caller so need to copy it.
self._name = decode_name(adv_data) or "?"
self._ble.gap_scan(None)
elif event == _IRQ_SCAN_DONE:
if self._scan_callback:
if self._addr:
# Found a device during the scan (and the scan was explicitly stopped).
self._scan_callback(self._addr_type, self._addr, self._name)
self._scan_callback = None
else:
# Scan timed out.
self._scan_callback(None, None, None)
elif event == _IRQ_PERIPHERAL_CONNECT:
# Connect successful.
conn_handle, addr_type, addr = data
if addr_type == self._addr_type and addr == self._addr:
self._conn_handle = conn_handle
self._ble.gattc_discover_services(self._conn_handle)
elif event == _IRQ_PERIPHERAL_DISCONNECT:
# Disconnect (either initiated by us or the remote end).
conn_handle, _, _ = data
if conn_handle == self._conn_handle:
# If it was initiated by us, it'll already be reset.
self._reset()
elif event == _IRQ_GATTC_SERVICE_RESULT:
# Connected device returned a service.
conn_handle, start_handle, end_handle, uuid = data
print("service", data)
if conn_handle == self._conn_handle and uuid == _UART_SERVICE_UUID:
self._start_handle, self._end_handle = start_handle, end_handle
elif event == _IRQ_GATTC_SERVICE_DONE:
# Service query complete.
if self._start_handle and self._end_handle:
self._ble.gattc_discover_characteristics(
self._conn_handle, self._start_handle, self._end_handle
)
else:
print("Failed to find uart service.")
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
# Connected device returned a characteristic.
conn_handle, def_handle, value_handle, properties, uuid = data
if conn_handle == self._conn_handle and uuid == _UART_RX_CHAR_UUID:
self._rx_handle = value_handle
if conn_handle == self._conn_handle and uuid == _UART_TX_CHAR_UUID:
self._tx_handle = value_handle
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
# Characteristic query complete.
if self._tx_handle is not None and self._rx_handle is not None:
# We've finished connecting and discovering device, fire the connect callback.
if self._conn_callback:
self._conn_callback()
else:
print("Failed to find uart rx characteristic.")
elif event == _IRQ_GATTC_WRITE_DONE:
conn_handle, value_handle, status = data
print("TX complete")
elif event == _IRQ_GATTC_NOTIFY:
conn_handle, value_handle, notify_data = data
if conn_handle == self._conn_handle and value_handle == self._tx_handle:
if self._notify_callback:
self._notify_callback(notify_data)
# Returns true if we've successfully connected and discovered characteristics.
def is_connected(self):
return (
self._conn_handle is not None
and self._tx_handle is not None
and self._rx_handle is not None
)
# Find a device advertising the environmental sensor service.
def scan(self, callback=None):
self._addr_type = None
self._addr = None
self._scan_callback = callback
self._ble.gap_scan(2000, 30000, 30000)
# Connect to the specified device (otherwise use cached address from a scan).
def connect(self, addr_type=None, addr=None, callback=None):
self._addr_type = addr_type or self._addr_type
self._addr = addr or self._addr
self._conn_callback = callback
if self._addr_type is None or self._addr is None:
return False
self._ble.gap_connect(self._addr_type, self._addr)
return True
# Disconnect from current device.
def disconnect(self):
if not self._conn_handle:
return
self._ble.gap_disconnect(self._conn_handle)
self._reset()
# Send data over the UART
def write(self, v, response=False):
if not self.is_connected():
return
self._ble.gattc_write(self._conn_handle, self._rx_handle, v, 1 if response else 0)
# Set handler for when data is received over the UART.
def on_notify(self, callback):
self._notify_callback = callback
def demo():
ble = bluetooth.BLE()
central = BLESimpleCentral(ble)
not_found = False
def on_scan(addr_type, addr, name):
if addr_type is not None:
print("Found peripheral:", addr_type, addr, name)
central.connect()
else:
nonlocal not_found
not_found = True
print("No peripheral found.")
central.scan(callback=on_scan)
# Wait for connection...
while not central.is_connected():
time.sleep_ms(100)
if not_found:
return
print("Connected")
def on_rx(v):
print("RX", v)
central.on_notify(on_rx)
with_response = False
i = 0
while central.is_connected():
try:
v = str(i) + "_"
print("TX", v)
central.write(v, with_response)
except:
print("TX failed")
i += 1
time.sleep_ms(400 if with_response else 30)
print("Disconnected")
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,101 @@
# This example demonstrates a UART periperhal.
import bluetooth
import random
import struct
import time
from ble_advertising import advertising_payload
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_TX = (
bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_READ | _FLAG_NOTIFY,
)
_UART_RX = (
bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE,
)
_UART_SERVICE = (
_UART_UUID,
(_UART_TX, _UART_RX),
)
class BLESimplePeripheral:
def __init__(self, ble, name="mpy-uart"):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,))
self._connections = set()
self._write_callback = None
self._payload = advertising_payload(name=name, services=[_UART_UUID])
self._advertise()
def _irq(self, event, data):
# Track connections so we can send notifications.
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
print("New connection", conn_handle)
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
print("Disconnected", conn_handle)
self._connections.remove(conn_handle)
# Start advertising again to allow a new connection.
self._advertise()
elif event == _IRQ_GATTS_WRITE:
conn_handle, value_handle = data
value = self._ble.gatts_read(value_handle)
if value_handle == self._handle_rx and self._write_callback:
self._write_callback(value)
def send(self, data):
for conn_handle in self._connections:
self._ble.gatts_notify(conn_handle, self._handle_tx, data)
def is_connected(self):
return len(self._connections) > 0
def _advertise(self, interval_us=500000):
print("Starting advertising")
self._ble.gap_advertise(interval_us, adv_data=self._payload)
def on_write(self, callback):
self._write_callback = callback
def demo():
ble = bluetooth.BLE()
p = BLESimplePeripheral(ble)
def on_rx(v):
print("RX", v)
p.on_write(on_rx)
i = 0
while True:
if p.is_connected():
# Short burst of queued notifications.
for _ in range(3):
data = str(i) + "_"
print("TX", data)
p.send(data)
i += 1
time.sleep_ms(100)
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,97 @@
# This example demonstrates a simple temperature sensor peripheral.
#
# The sensor's local value updates every second, and it will notify
# any connected central every 10 seconds.
import bluetooth
import random
import struct
import time
from ble_advertising import advertising_payload
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_INDICATE_DONE = const(20)
_FLAG_READ = const(0x0002)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
# org.bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
# org.bluetooth.characteristic.temperature
_TEMP_CHAR = (
bluetooth.UUID(0x2A6E),
_FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE,
)
_ENV_SENSE_SERVICE = (
_ENV_SENSE_UUID,
(_TEMP_CHAR,),
)
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
class BLETemperature:
def __init__(self, ble, name="mpy-temp"):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
self._connections = set()
self._payload = advertising_payload(
name=name, services=[_ENV_SENSE_UUID], appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER
)
self._advertise()
def _irq(self, event, data):
# Track connections so we can send notifications.
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
self._connections.remove(conn_handle)
# Start advertising again to allow a new connection.
self._advertise()
elif event == _IRQ_GATTS_INDICATE_DONE:
conn_handle, value_handle, status = data
def set_temperature(self, temp_deg_c, notify=False, indicate=False):
# Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
# Write the local value, ready for a central to read.
self._ble.gatts_write(self._handle, struct.pack("<h", int(temp_deg_c * 100)))
if notify or indicate:
for conn_handle in self._connections:
if notify:
# Notify connected centrals.
self._ble.gatts_notify(conn_handle, self._handle)
if indicate:
# Indicate connected centrals.
self._ble.gatts_indicate(conn_handle, self._handle)
def _advertise(self, interval_us=500000):
self._ble.gap_advertise(interval_us, adv_data=self._payload)
def demo():
ble = bluetooth.BLE()
temp = BLETemperature(ble)
t = 25
i = 0
while True:
# Write every second, notify every 10 seconds.
i = (i + 1) % 10
temp.set_temperature(t, notify=i == 0, indicate=False)
# Random walk the temperature.
t += random.uniform(-0.5, 0.5)
time.sleep_ms(1000)
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,263 @@
# This example finds and connects to a BLE temperature sensor (e.g. the one in ble_temperature.py).
import bluetooth
import random
import struct
import time
import micropython
from ble_advertising import decode_services, decode_name
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_IRQ_GATTS_READ_REQUEST = const(4)
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
_IRQ_PERIPHERAL_CONNECT = const(7)
_IRQ_PERIPHERAL_DISCONNECT = const(8)
_IRQ_GATTC_SERVICE_RESULT = const(9)
_IRQ_GATTC_SERVICE_DONE = const(10)
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
_IRQ_GATTC_READ_RESULT = const(15)
_IRQ_GATTC_READ_DONE = const(16)
_IRQ_GATTC_WRITE_DONE = const(17)
_IRQ_GATTC_NOTIFY = const(18)
_IRQ_GATTC_INDICATE = const(19)
_ADV_IND = const(0x00)
_ADV_DIRECT_IND = const(0x01)
_ADV_SCAN_IND = const(0x02)
_ADV_NONCONN_IND = const(0x03)
# org.bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
# org.bluetooth.characteristic.temperature
_TEMP_UUID = bluetooth.UUID(0x2A6E)
_TEMP_CHAR = (
_TEMP_UUID,
bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
)
_ENV_SENSE_SERVICE = (
_ENV_SENSE_UUID,
(_TEMP_CHAR,),
)
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
class BLETemperatureCentral:
def __init__(self, ble):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
self._reset()
def _reset(self):
# Cached name and address from a successful scan.
self._name = None
self._addr_type = None
self._addr = None
# Cached value (if we have one)
self._value = None
# Callbacks for completion of various operations.
# These reset back to None after being invoked.
self._scan_callback = None
self._conn_callback = None
self._read_callback = None
# Persistent callback for when new data is notified from the device.
self._notify_callback = None
# Connected device.
self._conn_handle = None
self._start_handle = None
self._end_handle = None
self._value_handle = None
def _irq(self, event, data):
if event == _IRQ_SCAN_RESULT:
addr_type, addr, adv_type, rssi, adv_data = data
if adv_type in (_ADV_IND, _ADV_DIRECT_IND) and _ENV_SENSE_UUID in decode_services(
adv_data
):
# Found a potential device, remember it and stop scanning.
self._addr_type = addr_type
self._addr = bytes(
addr
) # Note: addr buffer is owned by caller so need to copy it.
self._name = decode_name(adv_data) or "?"
self._ble.gap_scan(None)
elif event == _IRQ_SCAN_DONE:
if self._scan_callback:
if self._addr:
# Found a device during the scan (and the scan was explicitly stopped).
self._scan_callback(self._addr_type, self._addr, self._name)
self._scan_callback = None
else:
# Scan timed out.
self._scan_callback(None, None, None)
elif event == _IRQ_PERIPHERAL_CONNECT:
# Connect successful.
conn_handle, addr_type, addr = data
if addr_type == self._addr_type and addr == self._addr:
self._conn_handle = conn_handle
self._ble.gattc_discover_services(self._conn_handle)
elif event == _IRQ_PERIPHERAL_DISCONNECT:
# Disconnect (either initiated by us or the remote end).
conn_handle, _, _ = data
if conn_handle == self._conn_handle:
# If it was initiated by us, it'll already be reset.
self._reset()
elif event == _IRQ_GATTC_SERVICE_RESULT:
# Connected device returned a service.
conn_handle, start_handle, end_handle, uuid = data
if conn_handle == self._conn_handle and uuid == _ENV_SENSE_UUID:
self._start_handle, self._end_handle = start_handle, end_handle
elif event == _IRQ_GATTC_SERVICE_DONE:
# Service query complete.
if self._start_handle and self._end_handle:
self._ble.gattc_discover_characteristics(
self._conn_handle, self._start_handle, self._end_handle
)
else:
print("Failed to find environmental sensing service.")
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
# Connected device returned a characteristic.
conn_handle, def_handle, value_handle, properties, uuid = data
if conn_handle == self._conn_handle and uuid == _TEMP_UUID:
self._value_handle = value_handle
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
# Characteristic query complete.
if self._value_handle:
# We've finished connecting and discovering device, fire the connect callback.
if self._conn_callback:
self._conn_callback()
else:
print("Failed to find temperature characteristic.")
elif event == _IRQ_GATTC_READ_RESULT:
# A read completed successfully.
conn_handle, value_handle, char_data = data
if conn_handle == self._conn_handle and value_handle == self._value_handle:
self._update_value(char_data)
if self._read_callback:
self._read_callback(self._value)
self._read_callback = None
elif event == _IRQ_GATTC_READ_DONE:
# Read completed (no-op).
conn_handle, value_handle, status = data
elif event == _IRQ_GATTC_NOTIFY:
# The ble_temperature.py demo periodically notifies its value.
conn_handle, value_handle, notify_data = data
if conn_handle == self._conn_handle and value_handle == self._value_handle:
self._update_value(notify_data)
if self._notify_callback:
self._notify_callback(self._value)
# Returns true if we've successfully connected and discovered characteristics.
def is_connected(self):
return self._conn_handle is not None and self._value_handle is not None
# Find a device advertising the environmental sensor service.
def scan(self, callback=None):
self._addr_type = None
self._addr = None
self._scan_callback = callback
self._ble.gap_scan(2000, 30000, 30000)
# Connect to the specified device (otherwise use cached address from a scan).
def connect(self, addr_type=None, addr=None, callback=None):
self._addr_type = addr_type or self._addr_type
self._addr = addr or self._addr
self._conn_callback = callback
if self._addr_type is None or self._addr is None:
return False
self._ble.gap_connect(self._addr_type, self._addr)
return True
# Disconnect from current device.
def disconnect(self):
if not self._conn_handle:
return
self._ble.gap_disconnect(self._conn_handle)
self._reset()
# Issues an (asynchronous) read, will invoke callback with data.
def read(self, callback):
if not self.is_connected():
return
self._read_callback = callback
self._ble.gattc_read(self._conn_handle, self._value_handle)
# Sets a callback to be invoked when the device notifies us.
def on_notify(self, callback):
self._notify_callback = callback
def _update_value(self, data):
# Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
self._value = struct.unpack("<h", data)[0] / 100
return self._value
def value(self):
return self._value
def demo():
ble = bluetooth.BLE()
central = BLETemperatureCentral(ble)
not_found = False
def on_scan(addr_type, addr, name):
if addr_type is not None:
print("Found sensor:", addr_type, addr, name)
central.connect()
else:
nonlocal not_found
not_found = True
print("No sensor found.")
central.scan(callback=on_scan)
# Wait for connection...
while not central.is_connected():
time.sleep_ms(100)
if not_found:
return
print("Connected")
# Explicitly issue reads, using "print" as the callback.
while central.is_connected():
central.read(callback=print)
time.sleep_ms(2000)
# Alternative to the above, just show the most recently notified value.
# while central.is_connected():
# print(central.value())
# time.sleep_ms(2000)
print("Disconnected")
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,117 @@
# This example demonstrates a peripheral implementing the Nordic UART Service (NUS).
import bluetooth
from ble_advertising import advertising_payload
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_TX = (
bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_NOTIFY,
)
_UART_RX = (
bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
_FLAG_WRITE,
)
_UART_SERVICE = (
_UART_UUID,
(_UART_TX, _UART_RX),
)
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_COMPUTER = const(128)
class BLEUART:
def __init__(self, ble, name="mpy-uart", rxbuf=100):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
((self._tx_handle, self._rx_handle),) = self._ble.gatts_register_services((_UART_SERVICE,))
# Increase the size of the rx buffer and enable append mode.
self._ble.gatts_set_buffer(self._rx_handle, rxbuf, True)
self._connections = set()
self._rx_buffer = bytearray()
self._handler = None
# Optionally add services=[_UART_UUID], but this is likely to make the payload too large.
self._payload = advertising_payload(name=name, appearance=_ADV_APPEARANCE_GENERIC_COMPUTER)
self._advertise()
def irq(self, handler):
self._handler = handler
def _irq(self, event, data):
# Track connections so we can send notifications.
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
if conn_handle in self._connections:
self._connections.remove(conn_handle)
# Start advertising again to allow a new connection.
self._advertise()
elif event == _IRQ_GATTS_WRITE:
conn_handle, value_handle = data
if conn_handle in self._connections and value_handle == self._rx_handle:
self._rx_buffer += self._ble.gatts_read(self._rx_handle)
if self._handler:
self._handler()
def any(self):
return len(self._rx_buffer)
def read(self, sz=None):
if not sz:
sz = len(self._rx_buffer)
result = self._rx_buffer[0:sz]
self._rx_buffer = self._rx_buffer[sz:]
return result
def write(self, data):
for conn_handle in self._connections:
self._ble.gatts_notify(conn_handle, self._tx_handle, data)
def close(self):
for conn_handle in self._connections:
self._ble.gap_disconnect(conn_handle)
self._connections.clear()
def _advertise(self, interval_us=500000):
self._ble.gap_advertise(interval_us, adv_data=self._payload)
def demo():
import time
ble = bluetooth.BLE()
uart = BLEUART(ble)
def on_rx():
print("rx: ", uart.read().decode().strip())
uart.irq(handler=on_rx)
nums = [4, 8, 15, 16, 23, 42]
i = 0
try:
while True:
uart.write(str(nums[i]) + "\n")
i = (i + 1) % len(nums)
time.sleep_ms(1000)
except KeyboardInterrupt:
pass
uart.close()
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,82 @@
# Proof-of-concept of a REPL over BLE UART.
#
# Tested with the Adafruit Bluefruit app on Android.
# Set the EoL characters to \r\n.
import bluetooth
import io
import os
import micropython
import machine
from ble_uart_peripheral import BLEUART
_MP_STREAM_POLL = const(3)
_MP_STREAM_POLL_RD = const(0x0001)
# TODO: Remove this when STM32 gets machine.Timer.
if hasattr(machine, "Timer"):
_timer = machine.Timer(-1)
else:
_timer = None
# Batch writes into 50ms intervals.
def schedule_in(handler, delay_ms):
def _wrap(_arg):
handler()
if _timer:
_timer.init(mode=machine.Timer.ONE_SHOT, period=delay_ms, callback=_wrap)
else:
micropython.schedule(_wrap, None)
# Simple buffering stream to support the dupterm requirements.
class BLEUARTStream(io.IOBase):
def __init__(self, uart):
self._uart = uart
self._tx_buf = bytearray()
self._uart.irq(self._on_rx)
def _on_rx(self):
# Needed for ESP32.
if hasattr(os, "dupterm_notify"):
os.dupterm_notify(None)
def read(self, sz=None):
return self._uart.read(sz)
def readinto(self, buf):
avail = self._uart.read(len(buf))
if not avail:
return None
for i in range(len(avail)):
buf[i] = avail[i]
return len(avail)
def ioctl(self, op, arg):
if op == _MP_STREAM_POLL:
if self._uart.any():
return _MP_STREAM_POLL_RD
return 0
def _flush(self):
data = self._tx_buf[0:100]
self._tx_buf = self._tx_buf[100:]
self._uart.write(data)
if self._tx_buf:
schedule_in(self._flush, 50)
def write(self, buf):
empty = not self._tx_buf
self._tx_buf += buf
if empty:
schedule_in(self._flush, 50)
def start():
ble = bluetooth.BLE()
uart = BLEUART(ble, name="mpy-repl")
stream = BLEUARTStream(uart)
os.dupterm(stream)

View File

@@ -0,0 +1,51 @@
# import essential libraries
import pyb
lcd = pyb.LCD("x")
lcd.light(1)
# do 1 iteration of Conway's Game of Life
def conway_step():
for x in range(128): # loop over x coordinates
for y in range(32): # loop over y coordinates
# count number of neighbours
num_neighbours = (
lcd.get(x - 1, y - 1)
+ lcd.get(x, y - 1)
+ lcd.get(x + 1, y - 1)
+ lcd.get(x - 1, y)
+ lcd.get(x + 1, y)
+ lcd.get(x + 1, y + 1)
+ lcd.get(x, y + 1)
+ lcd.get(x - 1, y + 1)
)
# check if the centre cell is alive or not
self = lcd.get(x, y)
# apply the rules of life
if self and not (2 <= num_neighbours <= 3):
lcd.pixel(x, y, 0) # not enough, or too many neighbours: cell dies
elif not self and num_neighbours == 3:
lcd.pixel(x, y, 1) # exactly 3 neighbours around an empty cell: cell is born
# randomise the start
def conway_rand():
lcd.fill(0) # clear the LCD
for x in range(128): # loop over x coordinates
for y in range(32): # loop over y coordinates
lcd.pixel(x, y, pyb.rng() & 1) # set the pixel randomly
# loop for a certain number of frames, doing iterations of Conway's Game of Life
def conway_go(num_frames):
for i in range(num_frames):
conway_step() # do 1 iteration
lcd.show() # update the LCD
pyb.delay(50)
# testing
conway_rand()
conway_go(100)

View File

@@ -0,0 +1,8 @@
MPTOP = ../..
CFLAGS = -std=c99 -I. -I$(MPTOP) -DNO_QSTR
LDFLAGS = -L.
hello-embed: hello-embed.o -lmicropython
-lmicropython:
$(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP)

View File

@@ -0,0 +1,193 @@
MPTOP = ../..
-include mpconfigport.mk
include $(MPTOP)/py/mkenv.mk
all: lib
# OS name, for simple autoconfig
UNAME_S := $(shell uname -s)
# include py core make definitions
include $(MPTOP)/py/py.mk
INC += -I.
INC += -I..
INC += -I$(MPTOP)
INC += -I$(MPTOP)/ports/unix
INC += -I$(BUILD)
# compiler settings
CWARN = -Wall -Werror
CWARN += -Wpointer-arith -Wuninitialized
CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
# Some systems (eg MacOS) need -fno-common so that mp_state_ctx is placed in the BSS.
CFLAGS += -fno-common
# Debugging/Optimization
ifdef DEBUG
CFLAGS += -g
COPT = -O0
else
COPT = -Os #-DNDEBUG
# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra
# security for detecting buffer overflows. Some distros (Ubuntu at the very least)
# have it enabled by default.
#
# gcc already optimizes some printf calls to call puts and/or putchar. When
# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some
# printf calls will also be optimized to call __printf_chk (in glibc). Any
# printfs which get redirected to __printf_chk are then no longer synchronized
# with printfs that go through mp_printf.
#
# In MicroPython, we don't want to use the runtime library's printf but rather
# go through mp_printf, so that stdout is properly tied into streams, etc.
# This means that we either need to turn off _FORTIFY_SOURCE or provide our
# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE.
# It should also be noted that the use of printf in MicroPython is typically
# quite limited anyways (primarily for debug and some error reporting, etc
# in the unix version).
#
# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could
# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/
# Original patchset was introduced by
# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html .
#
# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater
CFLAGS += -U _FORTIFY_SOURCE
endif
# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed.
# The unix port of MicroPython on OSX must be compiled with clang,
# while cross-compile ports require gcc, so we test here for OSX and
# if necessary override the value of 'CC' set in py/mkenv.mk
ifeq ($(UNAME_S),Darwin)
CC = clang
# Use clang syntax for map file
LDFLAGS_ARCH = -Wl,-map,$@.map
else
# Use gcc syntax for map file
LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref
endif
LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
ifeq ($(MICROPY_FORCE_32BIT),1)
# Note: you may need to install i386 versions of dependency packages,
# starting with linux-libc-dev:i386
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(UNAME_S),Linux)
CFLAGS_MOD += -I/usr/include/i686-linux-gnu
endif
endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
INC += -I$(MPTOP)/shared/readline
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
SHARED_SRC_C_EXTRA += readline/readline.c
endif
ifeq ($(MICROPY_USE_READLINE),2)
CFLAGS_MOD += -DMICROPY_USE_READLINE=2
LDFLAGS_MOD += -lreadline
# the following is needed for BSD
#LDFLAGS_MOD += -ltermcap
endif
ifeq ($(MICROPY_PY_TIME),1)
CFLAGS_MOD += -DMICROPY_PY_TIME=1
SRC_MOD += modtime.c
endif
ifeq ($(MICROPY_PY_TERMIOS),1)
CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1
SRC_MOD += modtermios.c
endif
ifeq ($(MICROPY_PY_SOCKET),1)
CFLAGS_MOD += -DMICROPY_PY_SOCKET=1
SRC_MOD += modsocket.c
endif
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(MICROPY_STANDALONE),1)
LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include)
ifeq ($(MICROPY_FORCE_32BIT),1)
LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a
else
LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a
endif
else
LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi)
LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi)
endif
ifeq ($(UNAME_S),Linux)
LIBFFI_LDFLAGS_MOD += -ldl
endif
CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1
LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD)
SRC_MOD += modffi.c
endif
MAIN_C = main.c
# source files
SRC_C = $(addprefix ports/unix/,\
$(MAIN_C) \
gccollect.c \
unix_mphal.c \
input.c \
modmachine.c \
moduselect.c \
alloc.c \
coverage.c \
fatfs_port.c \
$(SRC_MOD) \
)
SHARED_SRC_C = $(addprefix shared/,\
libc/printf.c \
runtime/gchelper_generic.c \
timeutils/timeutils.c \
$(SHARED_SRC_C_EXTRA) \
)
OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SHARED_SRC_C)
# Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
include $(MPTOP)/py/mkrules.mk
# Value of configure's --host= option (required for cross-compilation).
# Deduce it from CROSS_COMPILE by default, but can be overridden.
ifneq ($(CROSS_COMPILE),)
CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE))
else
CROSS_COMPILE_HOST =
endif
deplibs: libffi axtls
# install-exec-recursive & install-data-am targets are used to avoid building
# docs and depending on makeinfo
libffi:
cd $(MPTOP)/lib/libffi; git clean -d -x -f
cd $(MPTOP)/lib/libffi; ./autogen.sh
mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \
../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \
make install-exec-recursive; make -C include install-data-am
axtls: $(MPTOP)/lib/axtls/README
cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config
cd $(MPTOP)/lib/axtls; make oldconfig -B
cd $(MPTOP)/lib/axtls; make clean
cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)"
$(MPTOP)/lib/axtls/README:
@echo "You cloned without --recursive, fetching submodules for you."
(cd $(MPTOP); git submodule update --init --recursive)

View File

@@ -0,0 +1,67 @@
Example of embedding MicroPython in a standalone C application
==============================================================
This directory contains a (very simple!) example of how to embed a MicroPython
in an existing C application.
A C application is represented by the file `hello-embed.c`. It executes a simple
Python statement which prints to the standard output.
Building the example
--------------------
Building the example is as simple as running:
make
It's worth to trace what's happening behind the scenes though:
1. As a first step, a MicroPython library is built. This is handled by a
separate makefile, `Makefile.upylib`. It is more or less complex, but the
good news is that you won't need to change anything in it, just use it
as is, the main `Makefile` shows how. What may require editing though is
a MicroPython configuration file. MicroPython is highly configurable, so
you would need to build a library suiting your application well, while
not bloating its size. Check the options in the file `mpconfigport.h`.
Included is a copy of the "minimal" Unix port, which should be a good start
for minimal embedding. For the list of all available options, see
`py/mpconfig.h`.
2. Once the MicroPython library is built, your application is compiled
and linked it. The main Makefile is very simple and shows that the changes
you would need to do to your application's `Makefile` (or other build
configuration) are also simple:
a) You would need to use C99 standard (you're using this 15+ years old
standard already, not a 25+ years old one, right?).
b) You need to provide a path to MicroPython's top-level dir, for includes.
c) You need to include `-DNO_QSTR` compile-time flag.
d) Otherwise, just link with the MicroPython library produced in step 1.
Out of tree build
-----------------
This example is set up to work out of the box, being part of the MicroPython
tree. Your application of course will be outside of its tree, but the
only thing you need to do is to pass `MPTOP` variable pointing to
MicroPython directory to both Makefiles (in this example, the main Makefile
automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget
to use a suitable value).
A practical way to embed MicroPython in your application is to include it
as a git submodule. Suppose you included it as `libs/micropython`. Then in
your main Makefile you would have something like:
~~~
MPTOP = libs/micropython
my_app: $(MY_OBJS) -lmicropython
-lmicropython:
$(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP)
~~~

View File

@@ -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 <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "py/builtin.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/gc.h"
#include "py/stackctrl.h"
static char heap[16384];
mp_obj_t execute_from_str(const char *str) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
qstr src_name = 1/*MP_QSTR_*/;
mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false);
mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT);
mp_obj_t module_fun = mp_compile(&pt, src_name, false);
mp_call_function_0(module_fun);
nlr_pop();
return 0;
} else {
// uncaught exception
return (mp_obj_t)nlr.ret_val;
}
}
int main() {
// Initialized stack limit
mp_stack_set_limit(40000 * (sizeof(void *) / 4));
// Initialize heap
gc_init(heap, heap + sizeof(heap));
// Initialize interpreter
mp_init();
const char str[] = "print('Hello world of easy embedding!')";
if (execute_from_str(str)) {
printf("Error\n");
}
}
uint mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
void nlr_jump_fail(void *val) {
printf("FATAL: uncaught NLR %p\n", val);
exit(1);
}

View File

@@ -0,0 +1 @@
#include "mpconfigport_minimal.h"

View File

@@ -0,0 +1,125 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 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.
*/
// options to control how MicroPython is built
#define MICROPY_ALLOC_PATH_MAX (PATH_MAX)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_FINALISER (0)
#define MICROPY_STACK_CHECK (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_READER_POSIX (1)
#define MICROPY_KBD_EXCEPTION (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (1)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_WARNINGS (0)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_STREAMS_NON_BLOCK (0)
#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_COMPILE (0)
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
#define MICROPY_PY_BUILTINS_FILTER (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_REVERSED (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY_BUILTINS_MIN_MAX (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_GC_COLLECT_RETVAL (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_IO_FILEIO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (1)
#define MICROPY_PY_SYS_EXIT (0)
#define MICROPY_PY_SYS_PLATFORM "linux"
#define MICROPY_PY_SYS_MAXSIZE (0)
#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen"
#define MICROPY_PY_SYS_STDFILES (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_UCTYPES (0)
#define MICROPY_PY_UZLIB (0)
#define MICROPY_PY_UJSON (0)
#define MICROPY_PY_UOS (1)
#define MICROPY_PY_URE (0)
#define MICROPY_PY_UHEAPQ (0)
#define MICROPY_PY_UHASHLIB (0)
#define MICROPY_PY_UBINASCII (0)
#define MICROPY_PORT_ROOT_POINTERS \
//////////////////////////////////////////
// Do not change anything beyond this line
//////////////////////////////////////////
#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
// Fall back to setjmp() implementation for discovery of GC pointers in registers.
#define MICROPY_GCREGS_SETJMP (1)
#endif
// type definitions for the specific machine
#ifdef __LP64__
typedef long mp_int_t; // must be pointer size
typedef unsigned long mp_uint_t; // must be pointer size
#else
// These are definitions for machines where sizeof(int) == sizeof(void*),
// regardless for actual size.
typedef int mp_int_t; // must be pointer size
typedef unsigned int mp_uint_t; // must be pointer size
#endif
// Cannot include <sys/types.h>, as it may lead to symbol name clashes
#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__)
typedef long long mp_off_t;
#else
typedef long mp_off_t;
#endif
// We need to provide a declaration/definition of alloca()
#ifdef __FreeBSD__
#include <stdlib.h>
#else
#include <alloca.h>
#endif

View File

@@ -0,0 +1,126 @@
This directory shows the best practices for using MicroPython hardware API
(`machine` module). `machine` module strives to provide consistent API
across various boards, with the aim to enable writing portable applications,
which would work from a board to board, from a system to another systems.
This is inherently a hard problem, because hardware is different from one
board type to another, and even from examplar of board to another. For
example, if your app requires an external LED, one user may connect it
to one GPIO pin, while another user may find it much more convinient to
use another pin. This of course applies to relays, buzzers, sensors, etc.
With complications above in mind, it's still possible to write portable
applications by using "low[est] denominator" subset of hardware API and
following simple rules outlined below. The applications won't be able
to rely on advanced hardware capabilities of a particular board and
will be limited to generic capabilities, but it's still possible to
write many useful applications in such a way, with the obvious benefit of
"write once - run everywhere" approach (only configuration for a particular
board is required).
The key to this approach is splitting your application into (at least)
2 parts:
* main application logic
* hardware configuration
The key point is that hardware configuration should be a separate file
(module in Python terms). A good name would be `hwconfig.py`, and that's
how we'll call it from now on. Another key point is that main application
should never instantiate (construct) hardware objects directly. Instead,
they should be defined in `hwconfig.py`, and main application should
import and reference hardware objects via this module. The simplest
application of this idea would look like:
`hwconfig.py`:
from machine import Pin
LED = Pin("A3", Pin.OUT)
`app.py`:
from hwconfig import *
import utime
while True:
LED.value(1)
utime.sleep_ms(500)
LED.value(0)
utime.sleep_ms(500)
To deploy this application to a particular board, a user will need:
1. Edit `hwconfig.py` to adjust Pin and other hardware peripheral
parameters and locations.
2. Actually deploy `hwconfig.py` and `app.py` to a board (e.g. copy to
board's filesystem, or build new firmware with these modules frozen
into it).
Note that there's no need to edit the main application code! (Which may
be complex, while `hwconfig.py` should usually remain short enough, and
focused solely on hardware configuration).
An obvious improvement to this approach is the following. There're few
well-known boards which run MicroPython, and most of them include an
onboard LED. So, to help users of these boards to do configuration
quickly (that's especially important for novice users, for who may
be stumped by the need to reach out to a board reference to find LED
pin assignments), `hwconfig.py` your application ships may include
commented out sections with working configurations for different
boards. The step 1 above then will be:
1. Look thru `hwconfig.py` to find a section which either exactly
matches your board, or the closest to it. Uncomment, and if any
adjustments required, apply them.
It's important to keep in mind that adjustments may be always required,
and that there may be users whose configuration doesn't match any of
the available. So, always include a section or instructions for them.
Consider for example that even on a supported board, user may want to
blink not an on-board LED, but the one they connected externally.
MicroPython's Hardware API offers portability not just among "supported"
boards, but to any board at all, so make sure users can enjoy it.
There's next step of improvement to make. While having one `hwconfig.py`
with many sections would work for smaller projects with few hardware
objects, it may become more cumbersome to maintain both on programmer's
and user's sides for larger projects. Then instead of single
`hwconfig.py` file, you can provide few "template" ones for well-known
boards:
* `hwconfig_pyboard.py`
* `hwconfig_wipy.py`
* `hwconfig_esp8266.py`
* etc.
Then step 1 above will be:
1. Look thru available `hwconfig_*.py` files and find one which matches
your board the best, then rename to `hwconfig.py` and make adjustments,
if any.
Again, please keep in mind that there may be users whose hardware will be
completely unlike you heard of. Give them some helpful hints too, perhaps
provide `hwconfig_custom.py` with some instructions.
That's where we stop with improvements to the "separate file for hardware
configuration" idea, as it is already pretty flexible and viable. An
application in this directory shows it in practice, using slightly less
trivial example than just a blinking LED: `soft_pwm.py` implements a
software PWM (pulse width modulation) to produce an LED fade-in/fade-out
effect - without any dependence on hardware PWM availability.
Note that improvements to board configuration handling may continue further.
For example, one may invent a "configuration manager" helper module which will
try to detect current board (among well-known ones), and load appropriate
`hwconfig_*.py` - this assumes that a user would lazily deploy them all
(or that application will be automatically installed, e.g. using MicroPython's
`upip` package manager). The key point in this case remains the same as
elaborated above - always assume there can, and will be a custom configuration,
and it should be well supported. So, any automatic detection should be
overridable by a user, and instructions how to do so are among the most
important you may provide for your application.
By following these best practices, you will use MicroPython at its full
potential, and let users enjoy it too. Good luck!

View File

@@ -0,0 +1,9 @@
import utime
from hwconfig import LED, BUTTON
# Light LED when (and while) a BUTTON is pressed
while 1:
LED.value(BUTTON.value())
# Don't burn CPU
utime.sleep_ms(10)

View File

@@ -0,0 +1,21 @@
import utime
import machine
from hwconfig import LED, BUTTON
# machine.time_pulse_us() function demo
print(
"""\
Let's play an interesting game:
You click button as fast as you can, and I tell you how slow you are.
Ready? Cliiiiick!
"""
)
while 1:
delay = machine.time_pulse_us(BUTTON, 1, 10 * 1000 * 1000)
if delay < 0:
print("Well, you're *really* slow")
else:
print("You are as slow as %d microseconds!" % delay)
utime.sleep_ms(10)

View File

@@ -0,0 +1,18 @@
# This is hwconfig for "emulation" for cases when there's no real hardware.
# It just prints information to console.
class LEDClass:
def __init__(self, id):
self.id = "LED(%d):" % id
def value(self, v):
print(self.id, v)
def on(self):
self.value(1)
def off(self):
self.value(0)
LED = LEDClass(1)
LED2 = LEDClass(12)

View File

@@ -0,0 +1,22 @@
from machine import Pin, Signal
# 96Boards/Qualcomm DragonBoard 410c
#
# By default, on-board LEDs are controlled by kernel LED driver.
# To make corresponding pins be available as normal GPIO,
# corresponding driver needs to be unbound first (as root):
# echo -n "soc:leds" >/sys/class/leds/apq8016-sbc:green:user1/device/driver/unbind
# Note that application also either should be run as root, or
# /sys/class/gpio ownership needs to be changed.
# Likewise, onboard buttons are controlled by gpio_keys driver.
# To release corresponding GPIOs:
# echo -n "gpio_keys" >/sys/class/input/input1/device/driver/unbind
# User LED 1 on gpio21
LED = Signal(Pin(21, Pin.OUT))
# User LED 2 on gpio120
LED2 = Signal(Pin(120, Pin.OUT))
# Button S3 on gpio107
BUTTON = Pin(107, Pin.IN)

View File

@@ -0,0 +1,5 @@
from machine import Pin, Signal
# ESP12 module as used by many boards
# Blue LED on pin 2, active low (inverted)
LED = Signal(2, Pin.OUT, invert=True)

View File

@@ -0,0 +1,13 @@
from machine import Pin, Signal
# Red LED on pin LED_RED also kown as A13
LED = Signal("LED_RED", Pin.OUT)
# Green LED on pin LED_GREEN also known as A14
LED2 = Signal("LED_GREEN", Pin.OUT)
# Yellow LED on pin LED_YELLOW also known as A15
LED3 = Signal("LED_YELLOW", Pin.OUT)
# Blue LED on pin LED_BLUE also known as B4
LED4 = Signal("LED_BLUE", Pin.OUT)

View File

@@ -0,0 +1,9 @@
from machine import Signal
# 96Boards Carbon board
# USR1 - User controlled led, connected to PD2
# USR2 - User controlled led, connected to PA15
# BT - Bluetooth indicator, connected to PB5.
# Note - 96b_carbon uses (at the time of writing) non-standard
# for Zephyr port device naming convention.
LED = Signal(("GPIOA", 15), Pin.OUT)

View File

@@ -0,0 +1,5 @@
from machine import Pin, Signal
# Freescale/NXP FRDM-K64F board
# Blue LED on port B, pin 21
LED = Signal(("GPIO_1", 21), Pin.OUT)

View File

@@ -0,0 +1,38 @@
import utime
from hwconfig import LED
# Using sleep_ms() gives pretty poor PWM resolution and
# brightness control, but we use it in the attempt to
# make this demo portable to even more boards (e.g. to
# those which don't provide sleep_us(), or provide, but
# it's not precise, like would be on non realtime OSes).
# We otherwise use 20ms period, to make frequency not less
# than 50Hz to avoid visible flickering (you may still see
# if you're unlucky).
def pwm_cycle(led, duty, cycles):
duty_off = 20 - duty
for i in range(cycles):
if duty:
led.on()
utime.sleep_ms(duty)
if duty_off:
led.off()
utime.sleep_ms(duty_off)
# At the duty setting of 1, an LED is still pretty bright, then
# at duty 0, it's off. This makes rather unsmooth transition, and
# breaks fade effect. So, we avoid value of 0 and oscillate between
# 1 and 20. Actually, highest values like 19 and 20 are also
# barely distinguishible (like, both of them too bright and burn
# your eye). So, improvement to the visible effect would be to use
# more steps (at least 10x), and then higher frequency, and use
# range which includes 1 but excludes values at the top.
while True:
# Fade in
for i in range(1, 21):
pwm_cycle(LED, i, 2)
# Fade out
for i in range(20, 0, -1):
pwm_cycle(LED, i, 2)

View File

@@ -0,0 +1,31 @@
# Like soft_pwm_uasyncio.py, but fading 2 LEDs with different phase.
# Also see original soft_pwm.py.
import uasyncio
from hwconfig import LED, LED2
async def pwm_cycle(led, duty, cycles):
duty_off = 20 - duty
for i in range(cycles):
if duty:
led.value(1)
await uasyncio.sleep_ms(duty)
if duty_off:
led.value(0)
await uasyncio.sleep_ms(duty_off)
async def fade_in_out(LED):
while True:
# Fade in
for i in range(1, 21):
await pwm_cycle(LED, i, 2)
# Fade out
for i in range(20, 0, -1):
await pwm_cycle(LED, i, 2)
loop = uasyncio.get_event_loop()
loop.create_task(fade_in_out(LED))
loop.call_later_ms(800, fade_in_out(LED2))
loop.run_forever()

View File

@@ -0,0 +1,28 @@
# See original soft_pwm.py for detailed comments.
import uasyncio
from hwconfig import LED
async def pwm_cycle(led, duty, cycles):
duty_off = 20 - duty
for i in range(cycles):
if duty:
led.value(1)
await uasyncio.sleep_ms(duty)
if duty_off:
led.value(0)
await uasyncio.sleep_ms(duty_off)
async def fade_in_out(LED):
while True:
# Fade in
for i in range(1, 21):
await pwm_cycle(LED, i, 2)
# Fade out
for i in range(20, 0, -1):
await pwm_cycle(LED, i, 2)
loop = uasyncio.get_event_loop()
loop.run_until_complete(fade_in_out(LED))

View File

@@ -0,0 +1,26 @@
import pyb
def led_angle(seconds_to_run_for):
# make LED objects
l1 = pyb.LED(1)
l2 = pyb.LED(2)
accel = pyb.Accel()
for i in range(20 * seconds_to_run_for):
# get x-axis
x = accel.x()
# turn on LEDs depending on angle
if x < -10:
l1.on()
l2.off()
elif x > 10:
l1.off()
l2.on()
else:
l1.off()
l2.off()
# delay so that loop runs at at 1/50ms = 20Hz
pyb.delay(50)

View File

@@ -0,0 +1,30 @@
try:
import micropython
except:
pass
def mandelbrot():
# returns True if c, complex, is in the Mandelbrot set
# @micropython.native
def in_set(c):
z = 0
for i in range(40):
z = z * z + c
if abs(z) > 60:
return False
return True
lcd.clear()
for u in range(91):
for v in range(31):
if in_set((u / 30 - 2) + (v / 15 - 1) * 1j):
lcd.set(u, v)
lcd.show()
# PC testing
import lcd
lcd = lcd.LCD(128, 32)
mandelbrot()

View File

@@ -0,0 +1,10 @@
# micropython module placeholder for CPython
# Dummy function decorators
def nodecor(x):
return x
bytecode = native = viper = nodecor

View File

@@ -0,0 +1 @@
*.mpy

View File

@@ -0,0 +1,37 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in btree so it can coexist)
MOD = btree_$(ARCH)
# Source files (.c or .py)
SRC = btree_c.c btree_py.py
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error="(void)" -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA)
CFLAGS += -I$(BTREE_DIR)/PORT/include
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
btree/bt_close.c \
btree/bt_conv.c \
btree/bt_delete.c \
btree/bt_get.c \
btree/bt_open.c \
btree/bt_overflow.c \
btree/bt_page.c \
btree/bt_put.c \
btree/bt_search.c \
btree/bt_seq.c \
btree/bt_split.c \
btree/bt_utils.c \
mpool/mpool.c \
)
include $(MPY_DIR)/py/dynruntime.mk
# btree needs gnu99 defined
CFLAGS += -std=gnu99

View File

@@ -0,0 +1,147 @@
#define MICROPY_PY_BTREE (1)
#include "py/dynruntime.h"
#include <unistd.h>
#if !defined(__linux__)
void *memcpy(void *dst, const void *src, size_t n) {
return mp_fun_table.memmove_(dst, src, n);
}
void *memset(void *s, int c, size_t n) {
return mp_fun_table.memset_(s, c, n);
}
#endif
void *memmove(void *dest, const void *src, size_t n) {
return mp_fun_table.memmove_(dest, src, n);
}
void *malloc(size_t n) {
void *ptr = m_malloc(n);
return ptr;
}
void *realloc(void *ptr, size_t n) {
mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__);
return NULL;
}
void *calloc(size_t n, size_t m) {
void *ptr = m_malloc(n * m);
// memory already cleared by conservative GC
return ptr;
}
void free(void *ptr) {
m_free(ptr);
}
void abort_(void) {
nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError)));
}
int native_errno;
#if defined(__linux__)
int *__errno_location (void)
#else
int *__errno (void)
#endif
{
return &native_errno;
}
ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) {
mp_obj_base_t* o = stream;
const mp_stream_p_t *stream_p = o->type->protocol;
mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
} else {
return out_sz;
}
}
ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) {
mp_obj_base_t* o = stream;
const mp_stream_p_t *stream_p = o->type->protocol;
mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
} else {
return out_sz;
}
}
off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) {
const mp_obj_base_t* o = stream;
const mp_stream_p_t *stream_p = o->type->protocol;
struct mp_stream_seek_t seek_s;
seek_s.offset = offset;
seek_s.whence = whence;
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno);
if (res == MP_STREAM_ERROR) {
return -1;
}
return seek_s.offset;
}
int mp_stream_posix_fsync(void *stream) {
mp_obj_base_t* o = stream;
const mp_stream_p_t *stream_p = o->type->protocol;
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno);
if (res == MP_STREAM_ERROR) {
return -1;
}
return res;
}
mp_obj_type_t btree_type;
#include "extmod/modbtree.c"
mp_map_elem_t btree_locals_dict_table[8];
STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) {
// Make sure we got a stream object
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
BTREEINFO openinfo = {0};
openinfo.flags = mp_obj_get_int(args[1]);
openinfo.cachesize = mp_obj_get_int(args[2]);
openinfo.psize = mp_obj_get_int(args[3]);
openinfo.minkeypage = mp_obj_get_int(args[4]);
DB *db = __bt_open(MP_OBJ_TO_PTR(args[0]), &btree_stream_fvtable, &openinfo, 0);
if (db == NULL) {
mp_raise_OSError(native_errno);
}
return MP_OBJ_FROM_PTR(btree_new(db, args[0]));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
btree_type.base.type = (void*)&mp_fun_table.type_type;
btree_type.name = MP_QSTR_btree;
btree_type.print = btree_print;
btree_type.getiter = btree_getiter;
btree_type.iternext = btree_iternext;
btree_type.binary_op = btree_binary_op;
btree_type.subscr = btree_subscr;
btree_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) };
btree_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) };
btree_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) };
btree_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) };
btree_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) };
btree_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) };
btree_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) };
btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) };
btree_type.locals_dict = (void*)&btree_locals_dict;
mp_store_global(MP_QSTR__open, MP_OBJ_FROM_PTR(&btree_open_obj));
mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL));
mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC));
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,3 @@
# Implemented in Python to support keyword arguments
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
return _open(stream, flags, cachesize, pagesize, minkeypage)

View File

@@ -0,0 +1,14 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module
MOD = features0
# Source files (.c or .py)
SRC = features0.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
# Include to get the rules for compiling and linking the module
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,40 @@
/* This example demonstrates the following features in a native module:
- defining a simple function exposed to Python
- defining a local, helper C function
- getting and creating integer objects
*/
// Include the header file to get access to the MicroPython API
#include "py/dynruntime.h"
// Helper function to compute factorial
STATIC mp_int_t factorial_helper(mp_int_t x) {
if (x == 0) {
return 1;
}
return x * factorial_helper(x - 1);
}
// This is the function which will be called from Python, as factorial(x)
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
// Extract the integer from the MicroPython input object
mp_int_t x = mp_obj_get_int(x_obj);
// Calculate the factorial
mp_int_t result = factorial_helper(x);
// Convert the result to a MicroPython integer object and return it
return mp_obj_new_int(result);
}
// Define a Python reference to the function above
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
// This is the entry point and is called when the module is imported
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
// This must be first, it sets up the globals dict and other things
MP_DYNRUNTIME_INIT_ENTRY
// Make the function available in the module's namespace
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
// This must be last, it restores the globals dict
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,14 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module
MOD = features1
# Source files (.c or .py)
SRC = features1.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
# Include to get the rules for compiling and linking the module
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,106 @@
/* This example demonstrates the following features in a native module:
- defining simple functions exposed to Python
- defining local, helper C functions
- defining constant integers and strings exposed to Python
- getting and creating integer objects
- creating Python lists
- raising exceptions
- allocating memory
- BSS and constant data (rodata)
- relocated pointers in rodata
*/
// Include the header file to get access to the MicroPython API
#include "py/dynruntime.h"
// BSS (zero) data
uint16_t data16[4];
// Constant data (rodata)
const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 };
const uint16_t table16[] = { 0x1000, 0x2000 };
// Constant data pointing to BSS/constant data
uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] };
const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] };
// A simple function that adds its 2 arguments (must be integers)
STATIC mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) {
mp_int_t x = mp_obj_get_int(x_in);
mp_int_t y = mp_obj_get_int(y_in);
return mp_obj_new_int(x + y);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
// A local helper function (not exposed to Python)
STATIC mp_int_t fibonacci_helper(mp_int_t x) {
if (x < MP_ARRAY_SIZE(table8)) {
return table8[x];
} else {
return fibonacci_helper(x - 1) + fibonacci_helper(x - 2);
}
}
// A function which computes Fibonacci numbers
STATIC mp_obj_t fibonacci(mp_obj_t x_in) {
mp_int_t x = mp_obj_get_int(x_in);
if (x < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number"));
}
return mp_obj_new_int(fibonacci_helper(x));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);
// A function that accesses the BSS data
STATIC mp_obj_t access(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// Create a list holding all items from data16
mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL));
for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) {
lst->items[i] = mp_obj_new_int(data16[i]);
}
return MP_OBJ_FROM_PTR(lst);
} else if (n_args == 1) {
// Get one item from data16
mp_int_t idx = mp_obj_get_int(args[0]) & 3;
return mp_obj_new_int(data16[idx]);
} else {
// Set one item in data16 (via table_ptr16a)
mp_int_t idx = mp_obj_get_int(args[0]) & 3;
*table_ptr16a[idx] = mp_obj_get_int(args[1]);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access);
// A function that allocates memory and creates a bytearray
STATIC mp_obj_t make_array(void) {
uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b));
for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) {
ptr[i] = *table_ptr16b[i];
}
return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array);
// This is the entry point and is called when the module is imported
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
// This must be first, it sets up the globals dict and other things
MP_DYNRUNTIME_INIT_ENTRY
// Messages can be printed as usualy
mp_printf(&mp_plat_print, "initialising module self=%p\n", self);
// Make the functions available in the module's namespace
mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj));
mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));
mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj));
mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj));
// Add some constants to the module's namespace
mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42));
mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON));
// This must be last, it restores the globals dict
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,14 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module
MOD = features2
# Source files (.c or .py)
SRC = main.c prod.c test.py
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
# Include to get the rules for compiling and linking the module
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,83 @@
/* This example demonstrates the following features in a native module:
- using floats
- defining additional code in Python (see test.py)
- have extra C code in a separate file (see prod.c)
*/
// Include the header file to get access to the MicroPython API
#include "py/dynruntime.h"
// Include the header for auxiliary C code for this module
#include "prod.h"
// Automatically detect if this module should include double-precision code.
// If double precision is supported by the target architecture then it can
// be used in native module regardless of what float setting the target
// MicroPython runtime uses (being none, float or double).
#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8))
#define USE_DOUBLE 1
#else
#define USE_DOUBLE 0
#endif
// A function that uses the default float type configured for the current target
// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level
STATIC mp_obj_t add(mp_obj_t x, mp_obj_t y) {
return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add);
// A function that explicitly uses single precision floats
STATIC mp_obj_t add_f(mp_obj_t x, mp_obj_t y) {
return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f);
#if USE_DOUBLE
// A function that explicitly uses double precision floats
STATIC mp_obj_t add_d(mp_obj_t x, mp_obj_t y) {
return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d);
#endif
// A function that computes the product of floats in an array.
// This function uses the most general C argument interface, which is more difficult
// to use but has access to the globals dict of the module via self->globals.
STATIC mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
// Check number of arguments is valid
mp_arg_check_num(n_args, n_kw, 1, 1, false);
// Extract buffer pointer and verify typecode
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW);
if (bufinfo.typecode != 'f') {
mp_raise_ValueError(MP_ERROR_TEXT("expecting float array"));
}
// Compute product, store result back in first element of array
float *ptr = bufinfo.buf;
float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr);
ptr[0] = prod;
return mp_const_none;
}
// This is the entry point and is called when the module is imported
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
// This must be first, it sets up the globals dict and other things
MP_DYNRUNTIME_INIT_ENTRY
// Make the functions available in the module's namespace
mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj));
mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj));
#if USE_DOUBLE
mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj));
#endif
// The productf function uses the most general C argument interface
mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf));
// This must be last, it restores the globals dict
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,9 @@
#include "prod.h"
float prod_array(int n, float *ar) {
float ans = 1;
for (int i = 0; i < n; ++i) {
ans *= ar[i];
}
return ans;
}

View File

@@ -0,0 +1 @@
float prod_array(int n, float *ar);

View File

@@ -0,0 +1,29 @@
# This Python code will be merged with the C code in main.c
import array
def isclose(a, b):
return abs(a - b) < 1e-3
def test():
tests = [
isclose(add(0.1, 0.2), 0.3),
isclose(add_f(0.1, 0.2), 0.3),
]
ar = array.array("f", [1, 2, 3.5])
productf(ar)
tests.append(isclose(ar[0], 7))
if "add_d" in globals():
tests.append(isclose(add_d(0.1, 0.2), 0.3))
print(tests)
if not all(tests):
raise SystemExit(1)
test()

View File

@@ -0,0 +1,14 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module
MOD = features3
# Source files (.c or .py)
SRC = features3.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
# Include to get the rules for compiling and linking the module
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,60 @@
/* This example demonstrates the following features in a native module:
- using types
- using constant objects
- creating dictionaries
*/
// Include the header file to get access to the MicroPython API.
#include "py/dynruntime.h"
// A function that returns a tuple of object types.
STATIC mp_obj_t get_types(void) {
return mp_obj_new_tuple(9, ((mp_obj_t []) {
MP_OBJ_FROM_PTR(&mp_type_type),
MP_OBJ_FROM_PTR(&mp_type_NoneType),
MP_OBJ_FROM_PTR(&mp_type_bool),
MP_OBJ_FROM_PTR(&mp_type_int),
MP_OBJ_FROM_PTR(&mp_type_str),
MP_OBJ_FROM_PTR(&mp_type_bytes),
MP_OBJ_FROM_PTR(&mp_type_tuple),
MP_OBJ_FROM_PTR(&mp_type_list),
MP_OBJ_FROM_PTR(&mp_type_dict),
}));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types);
// A function that returns a tuple of constant objects.
STATIC mp_obj_t get_const_objects(void) {
return mp_obj_new_tuple(5, ((mp_obj_t []) {
mp_const_none,
mp_const_false,
mp_const_true,
mp_const_empty_bytes,
mp_const_empty_tuple,
}));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects);
// A function that creates a dictionary from the given arguments.
STATIC mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) {
mp_obj_t dict = mp_obj_new_dict(n_args / 2);
for (; n_args >= 2; n_args -= 2, args += 2) {
mp_obj_dict_store(dict, args[0], args[1]);
}
return dict;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict);
// This is the entry point and is called when the module is imported.
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
// This must be first, it sets up the globals dict and other things.
MP_DYNRUNTIME_INIT_ENTRY
// Make the functions available in the module's namespace.
mp_store_global(MP_QSTR_make_dict, MP_OBJ_FROM_PTR(&make_dict_obj));
mp_store_global(MP_QSTR_get_types, MP_OBJ_FROM_PTR(&get_types_obj));
mp_store_global(MP_QSTR_get_const_objects, MP_OBJ_FROM_PTR(&get_const_objects_obj));
// This must be last, it restores the globals dict.
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,13 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in framebuf so it can coexist)
MOD = framebuf_$(ARCH)
# Source files (.c or .py)
SRC = framebuf.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,49 @@
#define MICROPY_PY_FRAMEBUF (1)
#include "py/dynruntime.h"
#if !defined(__linux__)
void *memset(void *s, int c, size_t n) {
return mp_fun_table.memset_(s, c, n);
}
#endif
mp_obj_type_t mp_type_framebuf;
#include "extmod/modframebuf.c"
mp_map_elem_t framebuf_locals_dict_table[10];
STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
mp_type_framebuf.base.type = (void*)&mp_type_type;
mp_type_framebuf.name = MP_QSTR_FrameBuffer;
mp_type_framebuf.make_new = framebuf_make_new;
mp_type_framebuf.buffer_p.get_buffer = framebuf_get_buffer;
framebuf_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill), MP_OBJ_FROM_PTR(&framebuf_fill_obj) };
framebuf_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill_rect), MP_OBJ_FROM_PTR(&framebuf_fill_rect_obj) };
framebuf_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_pixel), MP_OBJ_FROM_PTR(&framebuf_pixel_obj) };
framebuf_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_hline), MP_OBJ_FROM_PTR(&framebuf_hline_obj) };
framebuf_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_vline), MP_OBJ_FROM_PTR(&framebuf_vline_obj) };
framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) };
framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) };
framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
mp_type_framebuf.locals_dict = (void*)&framebuf_locals_dict;
mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf));
mp_store_global(MP_QSTR_FrameBuffer1, MP_OBJ_FROM_PTR(&legacy_framebuffer1_obj));
mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565));
mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB));
mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB));
mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8));
mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB));
mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB));
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,13 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in uheapq so it can coexist)
MOD = uheapq_$(ARCH)
# Source files (.c or .py)
SRC = uheapq.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,16 @@
#define MICROPY_PY_UHEAPQ (1)
#include "py/dynruntime.h"
#include "extmod/moduheapq.c"
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uheapq));
mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_uheapq_heappush_obj));
mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_uheapq_heappop_obj));
mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_uheapq_heapify_obj));
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,13 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in urandom so it can coexist)
MOD = urandom_$(ARCH)
# Source files (.c or .py)
SRC = urandom.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,33 @@
#define MICROPY_PY_URANDOM (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
#include "py/dynruntime.h"
// Dynamic native modules don't support a data section so these must go in the BSS
uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
uint8_t yasmarang_dat;
#include "extmod/modurandom.c"
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
yasmarang_pad = 0xeda4baba;
yasmarang_n = 69;
yasmarang_d = 233;
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_urandom));
mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_urandom_getrandbits_obj));
mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_urandom_seed_obj));
#if MICROPY_PY_URANDOM_EXTRA_FUNCS
mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_urandom_randrange_obj));
mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_urandom_randint_obj));
mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_urandom_choice_obj));
#if MICROPY_PY_BUILTINS_FLOAT
mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_urandom_random_obj));
mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_urandom_uniform_obj));
#endif
#endif
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,13 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in ure so it can coexist)
MOD = ure_$(ARCH)
# Source files (.c or .py)
SRC = ure.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,78 @@
#define MICROPY_STACK_CHECK (1)
#define MICROPY_PY_URE (1)
#define MICROPY_PY_URE_MATCH_GROUPS (1)
#define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
#define MICROPY_PY_URE_SUB (0) // requires vstr interface
#include <alloca.h>
#include "py/dynruntime.h"
#define STACK_LIMIT (2048)
const char *stack_top;
void mp_stack_check(void) {
// Assumes descending stack on target
volatile char dummy;
if (stack_top - &dummy >= STACK_LIMIT) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("maximum recursion depth exceeded"));
}
}
#if !defined(__linux__)
void *memcpy(void *dst, const void *src, size_t n) {
return mp_fun_table.memmove_(dst, src, n);
}
void *memset(void *s, int c, size_t n) {
return mp_fun_table.memset_(s, c, n);
}
#endif
void *memmove(void *dest, const void *src, size_t n) {
return mp_fun_table.memmove_(dest, src, n);
}
mp_obj_type_t match_type;
mp_obj_type_t re_type;
#include "extmod/modure.c"
mp_map_elem_t match_locals_dict_table[5];
STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
mp_map_elem_t re_locals_dict_table[3];
STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
char dummy;
stack_top = &dummy;
// Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section
// to copy in this key/value pair if they are specified as a struct, so assign them separately.
match_type.base.type = (void*)&mp_fun_table.type_type;
match_type.name = MP_QSTR_match;
match_type.print = match_print;
match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) };
match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) };
match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) };
match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) };
match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) };
match_type.locals_dict = (void*)&match_locals_dict;
re_type.base.type = (void*)&mp_fun_table.type_type;
re_type.name = MP_QSTR_ure;
re_type.print = re_print;
re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) };
re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) };
re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) };
re_type.locals_dict = (void*)&re_locals_dict;
mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj));
mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj));
mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&re_search_obj));
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,13 @@
# Location of top-level MicroPython directory
MPY_DIR = ../../..
# Name of module (different to built-in uzlib so it can coexist)
MOD = uzlib_$(ARCH)
# Source files (.c or .py)
SRC = uzlib.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -0,0 +1,35 @@
#define MICROPY_PY_UZLIB (1)
#include "py/dynruntime.h"
#if !defined(__linux__)
void *memset(void *s, int c, size_t n) {
return mp_fun_table.memset_(s, c, n);
}
#endif
mp_obj_type_t decompio_type;
#include "extmod/moduzlib.c"
mp_map_elem_t decompio_locals_dict_table[3];
STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
decompio_type.base.type = mp_fun_table.type_type;
decompio_type.name = MP_QSTR_DecompIO;
decompio_type.make_new = decompio_make_new;
decompio_type.protocol = &decompio_stream_p;
decompio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) };
decompio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) };
decompio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) };
decompio_type.locals_dict = (void*)&decompio_locals_dict;
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uzlib));
mp_store_global(MP_QSTR_decompress, MP_OBJ_FROM_PTR(&mod_uzlib_decompress_obj));
mp_store_global(MP_QSTR_DecompIO, MP_OBJ_FROM_PTR(&decompio_type));
MP_DYNRUNTIME_INIT_EXIT
}

View File

@@ -0,0 +1,30 @@
try:
import usocket as socket
except:
import socket
def main(use_stream=False):
s = socket.socket()
ai = socket.getaddrinfo("google.com", 80)
print("Address infos:", ai)
addr = ai[0][-1]
print("Connect address:", addr)
s.connect(addr)
if use_stream:
# MicroPython socket objects support stream (aka file) interface
# directly, but the line below is needed for CPython.
s = s.makefile("rwb", 0)
s.write(b"GET / HTTP/1.0\r\n\r\n")
print(s.read())
else:
s.send(b"GET / HTTP/1.0\r\n\r\n")
print(s.recv(4096))
s.close()
main()

View File

@@ -0,0 +1,38 @@
try:
import usocket as _socket
except:
import _socket
try:
import ussl as ssl
except:
import ssl
def main(use_stream=True):
s = _socket.socket()
ai = _socket.getaddrinfo("google.com", 443)
print("Address infos:", ai)
addr = ai[0][-1]
print("Connect address:", addr)
s.connect(addr)
s = ssl.wrap_socket(s)
print(s)
if use_stream:
# Both CPython and MicroPython SSLSocket objects support read() and
# write() methods.
s.write(b"GET / HTTP/1.0\r\n\r\n")
print(s.read(4096))
else:
# MicroPython SSLSocket objects implement only stream interface, not
# socket interface
s.send(b"GET / HTTP/1.0\r\n\r\n")
print(s.recv(4096))
s.close()
main()

View File

@@ -0,0 +1,65 @@
try:
import usocket as socket
except:
import socket
CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""
def main(micropython_optimize=False):
s = socket.socket()
# Binding to all interfaces - server will be accessible to other hosts!
ai = socket.getaddrinfo("0.0.0.0", 8080)
print("Bind address info:", ai)
addr = ai[0][-1]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://<this_host>:8080/")
counter = 0
while True:
res = s.accept()
client_sock = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_sock)
if not micropython_optimize:
# To read line-oriented protocol (like HTTP) from a socket (and
# avoid short read problem), it must be wrapped in a stream (aka
# file-like) object. That's how you do it in CPython:
client_stream = client_sock.makefile("rwb")
else:
# .. but MicroPython socket objects support stream interface
# directly, so calling .makefile() method is not required. If
# you develop application which will run only on MicroPython,
# especially on a resource-constrained embedded device, you
# may take this shortcut to save resources.
client_stream = client_sock
print("Request:")
req = client_stream.readline()
print(req)
while True:
h = client_stream.readline()
if h == b"" or h == b"\r\n":
break
print(h)
client_stream.write(CONTENT % counter)
client_stream.close()
if not micropython_optimize:
client_sock.close()
counter += 1
print()
main()

View File

@@ -0,0 +1,41 @@
# Do not use this code in real projects! Read
# http_server_simplistic_commented.py for details.
try:
import usocket as socket
except:
import socket
CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""
def main():
s = socket.socket()
ai = socket.getaddrinfo("0.0.0.0", 8080)
addr = ai[0][-1]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://<this_host>:8080/")
counter = 0
while True:
res = s.accept()
client_s = res[0]
client_addr = res[1]
req = client_s.recv(4096)
print("Request:")
print(req)
client_s.send(CONTENT % counter)
client_s.close()
counter += 1
print()
main()

View File

@@ -0,0 +1,77 @@
#
# MicroPython http_server_simplistic.py example
#
# This example shows how to write the smallest possible HTTP
# server in MicroPython. With comments and convenience code
# removed, this example can be compressed literally to ten
# lines. There's a catch though - read comments below for
# details, and use this code only for quick hacks, preferring
# http_server.py for "real thing".
#
try:
import usocket as socket
except:
import socket
CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""
def main():
s = socket.socket()
# Bind to (allow to be connected on ) all interfaces. This means
# this server will be accessible to other hosts on your local
# network, and if your server has direct (non-firewalled) connection
# to the Internet, then to anyone on the Internet. We bind to all
# interfaces to let this example work easily on embedded MicroPython
# targets, which you will likely access from another machine on your
# local network. Take care when running this on an Internet-connected
# machine though! Replace "0.0.0.0" with "127.0.0.1" if in doubt, to
# make the server accessible only on the machine it runs on.
ai = socket.getaddrinfo("0.0.0.0", 8080)
print("Bind address info:", ai)
addr = ai[0][-1]
# A port on which a socket listened remains inactive during some time.
# This means that if you run this sample, terminate it, and run again
# you will likely get an error. To avoid this timeout, set SO_REUSEADDR
# socket option.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://<this_host>:8080/")
counter = 0
while True:
res = s.accept()
client_s = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_s)
# We assume here that .recv() call will read entire HTTP request
# from client. This is usually true, at least on "big OS" systems
# like Linux/MacOS/Windows. But that doesn't have to be true in
# all cases, in particular on embedded systems, when there can
# easily be "short recv", where it returns much less than requested
# data size. That's why this example is called "simplistic" - it
# shows that writing a web server in Python that *usually works* is
# ten lines of code, and you can use this technique for quick hacks
# and experimentation. But don't do it like that in production
# applications - instead, parse HTTP request properly, as shown
# by http_server.py example.
req = client_s.recv(4096)
print("Request:")
print(req)
client_s.send(CONTENT % counter)
client_s.close()
counter += 1
print()
main()

View File

@@ -0,0 +1,99 @@
import ubinascii as binascii
try:
import usocket as socket
except:
import socket
import ussl as ssl
# This self-signed key/cert pair is randomly generated and to be used for
# testing/demonstration only. You should always generate your own key/cert.
key = binascii.unhexlify(
b"3082013b020100024100cc20643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef"
b"610a6a6ba14abb891745cd18a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f"
b"872d0203010001024100bb17a54aeb3dd7ae4edec05e775ca9632cf02d29c2a089b563b0"
b"d05cdf95aeca507de674553f28b4eadaca82d5549a86058f9996b07768686a5b02cb240d"
b"d9f1022100f4a63f5549e817547dca97b5c658038e8593cb78c5aba3c4642cc4cd031d86"
b"8f022100d598d870ffe4a34df8de57047a50b97b71f4d23e323f527837c9edae88c79483"
b"02210098560c89a70385c36eb07fd7083235c4c1184e525d838aedf7128958bedfdbb102"
b"2051c0dab7057a8176ca966f3feb81123d4974a733df0f958525f547dfd1c271f9022044"
b"6c2cafad455a671a8cf398e642e1be3b18a3d3aec2e67a9478f83c964c4f1f"
)
cert = binascii.unhexlify(
b"308201d53082017f020203e8300d06092a864886f70d01010505003075310b3009060355"
b"0406130258583114301206035504080c0b54686550726f76696e63653110300e06035504"
b"070c075468654369747931133011060355040a0c0a436f6d70616e7958595a3113301106"
b"0355040b0c0a436f6d70616e7958595a3114301206035504030c0b546865486f73744e61"
b"6d65301e170d3139313231383033333935355a170d3239313231353033333935355a3075"
b"310b30090603550406130258583114301206035504080c0b54686550726f76696e636531"
b"10300e06035504070c075468654369747931133011060355040a0c0a436f6d70616e7958"
b"595a31133011060355040b0c0a436f6d70616e7958595a3114301206035504030c0b5468"
b"65486f73744e616d65305c300d06092a864886f70d0101010500034b003048024100cc20"
b"643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef610a6a6ba14abb891745cd18"
b"a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f872d0203010001300d06092a"
b"864886f70d0101050500034100b0513fe2829e9ecbe55b6dd14c0ede7502bde5d46153c8"
b"e960ae3ebc247371b525caeb41bbcf34686015a44c50d226e66aef0a97a63874ca5944ef"
b"979b57f0b3"
)
CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""
def main(use_stream=True):
s = socket.socket()
# Binding to all interfaces - server will be accessible to other hosts!
ai = socket.getaddrinfo("0.0.0.0", 8443)
print("Bind address info:", ai)
addr = ai[0][-1]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to https://<this_host>:8443/")
counter = 0
while True:
res = s.accept()
client_s = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_s)
# CPython uses key keyfile/certfile arguments, but MicroPython uses key/cert
client_s = ssl.wrap_socket(client_s, server_side=True, key=key, cert=cert)
print(client_s)
print("Request:")
if use_stream:
# Both CPython and MicroPython SSLSocket objects support read() and
# write() methods.
# Browsers are prone to terminate SSL connection abruptly if they
# see unknown certificate, etc. We must continue in such case -
# next request they issue will likely be more well-behaving and
# will succeed.
try:
req = client_s.readline()
print(req)
while True:
h = client_s.readline()
if h == b"" or h == b"\r\n":
break
print(h)
if req:
client_s.write(CONTENT % counter)
except Exception as e:
print("Exception serving request:", e)
else:
print(client_s.recv(4096))
client_s.send(CONTENT % counter)
client_s.close()
counter += 1
print()
main()

View File

@@ -0,0 +1,60 @@
# Print a nice list of pins, their current settings, and available afs.
# Requires pins_af.py from ports/stm32/build-PYBV10/ directory.
import pyb
import pins_af
def af():
max_name_width = 0
max_af_width = 0
for pin_entry in pins_af.PINS_AF:
max_name_width = max(max_name_width, len(pin_entry[0]))
for af_entry in pin_entry[1:]:
max_af_width = max(max_af_width, len(af_entry[1]))
for pin_entry in pins_af.PINS_AF:
pin_name = pin_entry[0]
print("%-*s " % (max_name_width, pin_name), end="")
for af_entry in pin_entry[1:]:
print("%2d: %-*s " % (af_entry[0], max_af_width, af_entry[1]), end="")
print("")
def pins():
mode_str = {
pyb.Pin.IN: "IN",
pyb.Pin.OUT_PP: "OUT_PP",
pyb.Pin.OUT_OD: "OUT_OD",
pyb.Pin.AF_PP: "AF_PP",
pyb.Pin.AF_OD: "AF_OD",
pyb.Pin.ANALOG: "ANALOG",
}
pull_str = {pyb.Pin.PULL_NONE: "", pyb.Pin.PULL_UP: "PULL_UP", pyb.Pin.PULL_DOWN: "PULL_DOWN"}
width = [0, 0, 0, 0]
rows = []
for pin_entry in pins_af.PINS_AF:
row = []
pin_name = pin_entry[0]
pin = pyb.Pin(pin_name)
pin_mode = pin.mode()
row.append(pin_name)
row.append(mode_str[pin_mode])
row.append(pull_str[pin.pull()])
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
pin_af = pin.af()
for af_entry in pin_entry[1:]:
if pin_af == af_entry[0]:
af_str = "%d: %s" % (pin_af, af_entry[1])
break
else:
af_str = "%d" % pin_af
else:
af_str = ""
row.append(af_str)
for col in range(len(width)):
width[col] = max(width[col], len(row[col]))
rows.append(row)
for row in rows:
for col in range(len(width)):
print("%-*s " % (width[col], row[col]), end="")
print("")

View File

@@ -0,0 +1,54 @@
# pyboard testing functions for CPython
import time
def delay(n):
# time.sleep(float(n) / 1000)
pass
rand_seed = 1
def rng():
global rand_seed
# for these choice of numbers, see P L'Ecuyer, "Tables of linear congruential generators of different sizes and good lattice structure"
rand_seed = (rand_seed * 653276) % 8388593
return rand_seed
# LCD testing object for PC
# uses double buffering
class LCD:
def __init__(self, port):
self.width = 128
self.height = 32
self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)]
self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)]
def light(self, value):
pass
def fill(self, value):
for y in range(self.height):
for x in range(self.width):
self.buf1[y][x] = self.buf2[y][x] = value
def show(self):
print("") # blank line to separate frames
for y in range(self.height):
for x in range(self.width):
self.buf1[y][x] = self.buf2[y][x]
for y in range(self.height):
row = "".join(["*" if self.buf1[y][x] else " " for x in range(self.width)])
print(row)
def get(self, x, y):
if 0 <= x < self.width and 0 <= y < self.height:
return self.buf1[y][x]
else:
return 0
def pixel(self, x, y, value):
if 0 <= x < self.width and 0 <= y < self.height:
self.buf2[y][x] = value

View File

@@ -0,0 +1,35 @@
# Example using PIO to blink an LED and raise an IRQ at 1Hz.
import time
from machine import Pin
import rp2
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_1hz():
# fmt: off
# Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
irq(rel(0))
set(pins, 1)
set(x, 31) [5]
label("delay_high")
nop() [29]
jmp(x_dec, "delay_high")
# Cycles: 1 + 7 + 32 * (30 + 1) = 1000
set(pins, 0)
set(x, 31) [6]
label("delay_low")
nop() [29]
jmp(x_dec, "delay_low")
# fmt: on
# Create the StateMachine with the blink_1hz program, outputting on Pin(25).
sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
# Set the IRQ handler to print the millisecond timestamp.
sm.irq(lambda p: print(time.ticks_ms()))
# Start the StateMachine.
sm.active(1)

View File

@@ -0,0 +1,27 @@
# Example using PIO to turn on an LED via an explicit exec.
#
# Demonstrates:
# - using set_init and set_base
# - using StateMachine.exec
import time
from machine import Pin
import rp2
# Define an empty program that uses a single set pin.
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def prog():
pass
# Construct the StateMachine, binding Pin(25) to the set pin.
sm = rp2.StateMachine(0, prog, set_base=Pin(25))
# Turn on the set pin via an exec instruction.
sm.exec("set(pins, 1)")
# Sleep for 500ms.
time.sleep(0.5)
# Turn off the set pin via an exec instruction.
sm.exec("set(pins, 0)")

View File

@@ -0,0 +1,46 @@
# Example using PIO to wait for a pin change and raise an IRQ.
#
# Demonstrates:
# - PIO wrapping
# - PIO wait instruction, waiting on an input pin
# - PIO irq instruction, in blocking mode with relative IRQ number
# - setting the in_base pin for a StateMachine
# - setting an irq handler for a StateMachine
# - instantiating 2x StateMachine's with the same program and different pins
import time
from machine import Pin
import rp2
@rp2.asm_pio()
def wait_pin_low():
wrap_target()
wait(0, pin, 0)
irq(block, rel(0))
wait(1, pin, 0)
wrap()
def handler(sm):
# Print a (wrapping) timestamp, and the state machine object.
print(time.ticks_ms(), sm)
# Instantiate StateMachine(0) with wait_pin_low program on Pin(16).
pin16 = Pin(16, Pin.IN, Pin.PULL_UP)
sm0 = rp2.StateMachine(0, wait_pin_low, in_base=pin16)
sm0.irq(handler)
# Instantiate StateMachine(1) with wait_pin_low program on Pin(17).
pin17 = Pin(17, Pin.IN, Pin.PULL_UP)
sm1 = rp2.StateMachine(1, wait_pin_low, in_base=pin17)
sm1.irq(handler)
# Start the StateMachine's running.
sm0.active(1)
sm1.active(1)
# Now, when Pin(16) or Pin(17) is pulled low a message will be printed to the REPL.

View File

@@ -0,0 +1,45 @@
# Example of using PIO for PWM, and fading the brightness of an LED
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep
@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
# fmt: off
pull(noblock) .side(0)
mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
mov(y, isr) # ISR must be preloaded with PWM count max
label("pwmloop")
jmp(x_not_y, "skip")
nop() .side(1)
label("skip")
jmp(y_dec, "pwmloop")
# fmt: on
class PIOPWM:
def __init__(self, sm_id, pin, max_count, count_freq):
self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
# Use exec() to load max count into ISR
self._sm.put(max_count)
self._sm.exec("pull()")
self._sm.exec("mov(isr, osr)")
self._sm.active(1)
self._max_count = max_count
def set(self, value):
# Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
value = max(value, -1)
value = min(value, self._max_count)
self._sm.put(value)
# Pin 25 is LED on Pico boards
pwm = PIOPWM(0, 25, max_count=(1 << 16) - 1, count_freq=10_000_000)
while True:
for i in range(256):
pwm.set(i**2)
sleep(0.01)

View File

@@ -0,0 +1,105 @@
# Example using PIO to create a UART RX interface.
#
# To make it work you'll need a wire connecting GPIO4 and GPIO3.
#
# Demonstrates:
# - PIO shifting in data on a pin
# - PIO jmp(pin) instruction
# - PIO irq handler
# - using the second core via _thread
import _thread
from machine import Pin, UART
from rp2 import PIO, StateMachine, asm_pio
UART_BAUD = 9600
HARD_UART_TX_PIN = Pin(4, Pin.OUT)
PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP)
@asm_pio(
autopush=True,
push_thresh=8,
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
fifo_join=PIO.JOIN_RX,
)
def uart_rx_mini():
# fmt: off
# Wait for start bit
wait(0, pin, 0)
# Preload bit counter, delay until eye of first data bit
set(x, 7) [10]
# Loop 8 times
label("bitloop")
# Sample data
in_(pins, 1)
# Each iteration is 8 cycles
jmp(x_dec, "bitloop") [6]
# fmt: on
@asm_pio(
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
)
def uart_rx():
# fmt: off
label("start")
# Stall until start bit is asserted
wait(0, pin, 0)
# Preload bit counter, then delay until halfway through
# the first data bit (12 cycles incl wait, set).
set(x, 7) [10]
label("bitloop")
# Shift data bit into ISR
in_(pins, 1)
# Loop 8 times, each loop iteration is 8 cycles
jmp(x_dec, "bitloop") [6]
# Check stop bit (should be high)
jmp(pin, "good_stop")
# Either a framing error or a break. Set a sticky flag
# and wait for line to return to idle state.
irq(block, 4)
wait(1, pin, 0)
# Don't push data if we didn't see good framing.
jmp("start")
# No delay before returning to start; a little slack is
# important in case the TX clock is slightly too fast.
label("good_stop")
push(block)
# fmt: on
# The handler for a UART break detected by the PIO.
def handler(sm):
print("break", time.ticks_ms(), end=" ")
# Function for core1 to execute to write to the given UART.
def core1_task(uart, text):
uart.write(text)
# Set up the hard UART we're going to use to print characters.
uart = UART(1, UART_BAUD, tx=HARD_UART_TX_PIN)
for pio_prog in ("uart_rx_mini", "uart_rx"):
# Set up the state machine we're going to use to receive the characters.
sm = StateMachine(
0,
globals()[pio_prog],
freq=8 * UART_BAUD,
in_base=PIO_RX_PIN, # For WAIT, IN
jmp_pin=PIO_RX_PIN, # For JMP
)
sm.irq(handler)
sm.active(1)
# Tell core 1 to print some text to UART 1
text = "Hello, world from PIO, using {}!".format(pio_prog)
_thread.start_new_thread(core1_task, (uart, text))
# Echo characters received from PIO to the console.
for i in range(len(text)):
print(chr(sm.get() >> 24), end="")
print()

View File

@@ -0,0 +1,44 @@
# Example using PIO to create a UART TX interface
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
UART_BAUD = 115200
PIN_BASE = 10
NUM_UARTS = 8
@asm_pio(sideset_init=PIO.OUT_HIGH, out_init=PIO.OUT_HIGH, out_shiftdir=PIO.SHIFT_RIGHT)
def uart_tx():
# fmt: off
# Block with TX deasserted until data available
pull()
# Initialise bit counter, assert start bit for 8 cycles
set(x, 7) .side(0) [7]
# Shift out 8 data bits, 8 execution cycles per bit
label("bitloop")
out(pins, 1) [6]
jmp(x_dec, "bitloop")
# Assert stop bit for 8 cycles total (incl 1 for pull())
nop() .side(1) [6]
# fmt: on
# Now we add 8 UART TXs, on pins 10 to 17. Use the same baud rate for all of them.
uarts = []
for i in range(NUM_UARTS):
sm = StateMachine(
i, uart_tx, freq=8 * UART_BAUD, sideset_base=Pin(PIN_BASE + i), out_base=Pin(PIN_BASE + i)
)
sm.active(1)
uarts.append(sm)
# We can print characters from each UART by pushing them to the TX FIFO
def pio_uart_print(sm, s):
for c in s:
sm.put(ord(c))
# Print a different message from each UART
for i, u in enumerate(uarts):
pio_uart_print(u, "Hello from UART {}!\n".format(i))

View File

@@ -0,0 +1,59 @@
# Example using PIO to drive a set of WS2812 LEDs.
import array, time
from machine import Pin
import rp2
# Configure the number of WS2812 LEDs.
NUM_LEDS = 8
@rp2.asm_pio(
sideset_init=rp2.PIO.OUT_LOW,
out_shiftdir=rp2.PIO.SHIFT_LEFT,
autopull=True,
pull_thresh=24,
)
def ws2812():
# fmt: off
T1 = 2
T2 = 5
T3 = 3
wrap_target()
label("bitloop")
out(x, 1) .side(0) [T3 - 1]
jmp(not_x, "do_zero") .side(1) [T1 - 1]
jmp("bitloop") .side(1) [T2 - 1]
label("do_zero")
nop() .side(0) [T2 - 1]
wrap()
# fmt: on
# Create the StateMachine with the ws2812 program, outputting on Pin(22).
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(22))
# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)
# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I", [0 for _ in range(NUM_LEDS)])
# Cycle colours.
for i in range(4 * NUM_LEDS):
for j in range(NUM_LEDS):
r = j * 100 // (NUM_LEDS - 1)
b = 100 - j * 100 // (NUM_LEDS - 1)
if j != i % NUM_LEDS:
r >>= 3
b >>= 3
ar[j] = r << 16 | b
sm.put(ar, 8)
time.sleep_ms(50)
# Fade out.
for i in range(24):
for j in range(NUM_LEDS):
ar[j] = ar[j] >> 1 & 0x7F7F7F
sm.put(ar, 8)
time.sleep_ms(50)

View File

@@ -0,0 +1,25 @@
# Example using PWM to fade an LED.
import time
from machine import Pin, PWM
# Construct PWM object, with LED on Pin(25).
pwm = PWM(Pin(25))
# Set the PWM frequency.
pwm.freq(1000)
# Fade the LED in and out a few times.
duty = 0
direction = 1
for _ in range(8 * 256):
duty += direction
if duty > 255:
duty = 255
direction = -1
elif duty < 0:
duty = 0
direction = 1
pwm.duty_u16(duty * duty)
time.sleep(0.001)

View File

@@ -0,0 +1,47 @@
"""
switch.py
=========
Light up some leds when the USR switch on the pyboard is pressed.
Example Usage::
Micro Python v1.0.1 on 2014-05-12; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> import switch
>>> switch.run_loop()
Loop started.
Press Ctrl+C to break out of the loop.
"""
import pyb
switch = pyb.Switch()
red_led = pyb.LED(1)
green_led = pyb.LED(2)
orange_led = pyb.LED(3)
blue_led = pyb.LED(4)
all_leds = (red_led, green_led, orange_led, blue_led)
def run_loop(leds=all_leds):
"""
Start the loop.
:param `leds`: Which LEDs to light up upon switch press.
:type `leds`: sequence of LED objects
"""
print("Loop started.\nPress Ctrl+C to break out of the loop.")
while 1:
try:
if switch():
[led.on() for led in leds]
else:
[led.off() for led in leds]
except OSError: # VCPInterrupt # Ctrl+C in interpreter mode.
break
if __name__ == "__main__":
run_loop()

View File

@@ -0,0 +1,41 @@
import ffi
import uctypes
libc = ffi.open("libc.so.6")
print("libc:", libc)
print()
# Declare few functions
perror = libc.func("v", "perror", "s")
time = libc.func("i", "time", "p")
open = libc.func("i", "open", "si")
qsort = libc.func("v", "qsort", "piiC")
# And one variable
errno = libc.var("i", "errno")
print("time:", time)
print("UNIX time is:", time(None))
print()
perror("perror before error")
open("somethingnonexistent__", 0)
print("errno object:", errno)
print("errno value:", errno.get())
perror("perror after error")
print()
def cmp(pa, pb):
a = uctypes.bytearray_at(pa, 1)
b = uctypes.bytearray_at(pb, 1)
print("cmp:", a, b)
return a[0] - b[0]
cmp_cb = ffi.callback("i", cmp, "PP")
print("callback:", cmp_cb)
s = bytearray(b"foobar")
print("org string:", s)
qsort(s, len(s), 1, cmp_cb)
print("qsort'ed string:", s)

View File

@@ -0,0 +1,9 @@
# This example shows how to access Video BIOS memory area via machine.mem
# It requires root privilege and x86 legacy harfware (which has mentioned
# Video BIOS at all).
# It is expected to print 0xaa55, which is a signature at the start of
# Video BIOS.
import umachine as machine
print(hex(machine.mem16[0xC0000]))

View File

@@ -0,0 +1,34 @@
// Include MicroPython API.
#include "py/runtime.h"
// This is the function which will be called from Python as cexample.add_ints(a, b).
STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// Extract the ints from the micropython input objects.
int a = mp_obj_get_int(a_obj);
int b = mp_obj_get_int(b_obj);
// Calculate the addition and convert to MicroPython object.
return mp_obj_new_int(a + b);
}
// Define a Python reference to the function above.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
// Define module object.
const mp_obj_module_t example_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule);

View File

@@ -0,0 +1,15 @@
# Create an INTERFACE library for our C module.
add_library(usermod_cexample INTERFACE)
# Add our source files to the lib
target_sources(usermod_cexample INTERFACE
${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
)
# Add the current directory as an include directory.
target_include_directories(usermod_cexample INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
# Link our INTERFACE library to the usermod target.
target_link_libraries(usermod INTERFACE usermod_cexample)

View File

@@ -0,0 +1,9 @@
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)

View File

@@ -0,0 +1,17 @@
extern "C" {
#include <examplemodule.h>
// Here we implement the function using C++ code, but since it's
// declaration has to be compatible with C everything goes in extern "C" scope.
mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj) {
// Prove we have (at least) C++11 features.
const auto a = mp_obj_get_int(a_obj);
const auto b = mp_obj_get_int(b_obj);
const auto sum = [&]() {
return mp_obj_new_int(a + b);
} ();
// Prove we're being scanned for QSTRs.
mp_obj_t tup[] = {sum, MP_ROM_QSTR(MP_QSTR_hellocpp)};
return mp_obj_new_tuple(2, tup);
}
}

View File

@@ -0,0 +1,25 @@
#include <examplemodule.h>
// Define a Python reference to the function we'll make available.
// See example.cpp for the definition.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t cppexample_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cppexample) },
{ MP_ROM_QSTR(MP_QSTR_cppfunc), MP_ROM_PTR(&cppfunc_obj) },
};
STATIC MP_DEFINE_CONST_DICT(cppexample_module_globals, cppexample_module_globals_table);
// Define module object.
const mp_obj_module_t cppexample_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&cppexample_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule);

View File

@@ -0,0 +1,5 @@
// Include MicroPython API.
#include "py/runtime.h"
// Declare the function we'll make available in Python as cppexample.cppfunc().
extern mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj);

View File

@@ -0,0 +1,16 @@
# Create an INTERFACE library for our CPP module.
add_library(usermod_cppexample INTERFACE)
# Add our source files to the library.
target_sources(usermod_cppexample INTERFACE
${CMAKE_CURRENT_LIST_DIR}/example.cpp
${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
)
# Add the current directory as an include directory.
target_include_directories(usermod_cppexample INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
# Link our INTERFACE library to the usermod target.
target_link_libraries(usermod INTERFACE usermod_cppexample)

View File

@@ -0,0 +1,12 @@
CPPEXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add our source files to the respective variables.
SRC_USERMOD += $(CPPEXAMPLE_MOD_DIR)/examplemodule.c
SRC_USERMOD_CXX += $(CPPEXAMPLE_MOD_DIR)/example.cpp
# Add our module directory to the include path.
CFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR) -std=c++11
# We use C++ features so have to link against the standard library.
LDFLAGS_USERMOD += -lstdc++

View File

@@ -0,0 +1,11 @@
# This top-level micropython.cmake is responsible for listing
# the individual modules we want to include.
# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be
# used to prefix subdirectories.
# Add the C example.
include(${CMAKE_CURRENT_LIST_DIR}/cexample/micropython.cmake)
# Add the CPP example.
include(${CMAKE_CURRENT_LIST_DIR}/cppexample/micropython.cmake)