micropython: add micropython component
This commit is contained in:
@@ -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.
|
@@ -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
|
@@ -0,0 +1,2 @@
|
||||
# cardread.py
|
||||
# This is called when the user enters cardreader mode. It does nothing.
|
@@ -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
|
34
components/language/micropython/examples/accel_i2c.py
Normal file
34
components/language/micropython/examples/accel_i2c.py
Normal 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)
|
20
components/language/micropython/examples/accellog.py
Normal file
20
components/language/micropython/examples/accellog.py
Normal 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
|
87
components/language/micropython/examples/asmled.py
Normal file
87
components/language/micropython/examples/asmled.py
Normal 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)
|
59
components/language/micropython/examples/asmsum.py
Normal file
59
components/language/micropython/examples/asmsum.py
Normal 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)
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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)
|
51
components/language/micropython/examples/conwaylife.py
Normal file
51
components/language/micropython/examples/conwaylife.py
Normal 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)
|
@@ -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)
|
@@ -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)
|
67
components/language/micropython/examples/embedding/README.md
Normal file
67
components/language/micropython/examples/embedding/README.md
Normal 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)
|
||||
~~~
|
@@ -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);
|
||||
}
|
@@ -0,0 +1 @@
|
||||
#include "mpconfigport_minimal.h"
|
@@ -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
|
126
components/language/micropython/examples/hwapi/README.md
Normal file
126
components/language/micropython/examples/hwapi/README.md
Normal 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!
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
@@ -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)
|
38
components/language/micropython/examples/hwapi/soft_pwm.py
Normal file
38
components/language/micropython/examples/hwapi/soft_pwm.py
Normal 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)
|
@@ -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()
|
@@ -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))
|
26
components/language/micropython/examples/ledangle.py
Normal file
26
components/language/micropython/examples/ledangle.py
Normal 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)
|
30
components/language/micropython/examples/mandel.py
Normal file
30
components/language/micropython/examples/mandel.py
Normal 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()
|
10
components/language/micropython/examples/micropython.py
Normal file
10
components/language/micropython/examples/micropython.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# micropython module placeholder for CPython
|
||||
|
||||
# Dummy function decorators
|
||||
|
||||
|
||||
def nodecor(x):
|
||||
return x
|
||||
|
||||
|
||||
bytecode = native = viper = nodecor
|
1
components/language/micropython/examples/natmod/.gitignore
vendored
Normal file
1
components/language/micropython/examples/natmod/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.mpy
|
@@ -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
|
147
components/language/micropython/examples/natmod/btree/btree_c.c
Normal file
147
components/language/micropython/examples/natmod/btree/btree_c.c
Normal 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
|
||||
}
|
@@ -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)
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -0,0 +1 @@
|
||||
float prod_array(int n, float *ar);
|
@@ -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()
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
13
components/language/micropython/examples/natmod/ure/Makefile
Normal file
13
components/language/micropython/examples/natmod/ure/Makefile
Normal 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
|
78
components/language/micropython/examples/natmod/ure/ure.c
Normal file
78
components/language/micropython/examples/natmod/ure/ure.c
Normal 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
|
||||
}
|
@@ -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
|
@@ -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
|
||||
}
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
60
components/language/micropython/examples/pins.py
Normal file
60
components/language/micropython/examples/pins.py
Normal 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("")
|
54
components/language/micropython/examples/pyb.py
Normal file
54
components/language/micropython/examples/pyb.py
Normal 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
|
35
components/language/micropython/examples/rp2/pio_1hz.py
Normal file
35
components/language/micropython/examples/rp2/pio_1hz.py
Normal 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)
|
27
components/language/micropython/examples/rp2/pio_exec.py
Normal file
27
components/language/micropython/examples/rp2/pio_exec.py
Normal 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)")
|
@@ -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.
|
45
components/language/micropython/examples/rp2/pio_pwm.py
Normal file
45
components/language/micropython/examples/rp2/pio_pwm.py
Normal 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)
|
105
components/language/micropython/examples/rp2/pio_uart_rx.py
Normal file
105
components/language/micropython/examples/rp2/pio_uart_rx.py
Normal 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()
|
44
components/language/micropython/examples/rp2/pio_uart_tx.py
Normal file
44
components/language/micropython/examples/rp2/pio_uart_tx.py
Normal 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))
|
59
components/language/micropython/examples/rp2/pio_ws2812.py
Normal file
59
components/language/micropython/examples/rp2/pio_ws2812.py
Normal 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)
|
25
components/language/micropython/examples/rp2/pwm_fade.py
Normal file
25
components/language/micropython/examples/rp2/pwm_fade.py
Normal 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)
|
47
components/language/micropython/examples/switch.py
Normal file
47
components/language/micropython/examples/switch.py
Normal 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()
|
41
components/language/micropython/examples/unix/ffi_example.py
Normal file
41
components/language/micropython/examples/unix/ffi_example.py
Normal 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)
|
@@ -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]))
|
@@ -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);
|
@@ -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)
|
@@ -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)
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
@@ -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);
|
@@ -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)
|
@@ -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++
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user