stmhal: Add documentation in comments, and script to generate HTML.

Decided to write own script to pull documentation from comments in C code.
Style for writing auto generated documentation is: start line with ///
and then use standard markdown to write the comment.  Keywords
recognised by the scraper begin with backslash.  See code for examples.

Running: python gendoc.py modpyb.c accel.c adc.c dac.c extint.c i2c.c
led.c pin.c rng.c servo.c spi.c uart.c usrsw.c, will generate a HTML
structure in gendoc-out/.

gendoc.py is crude but functional.  Needed something quick, and this was
it.
pull/534/merge
Damien George 2014-04-29 22:55:34 +01:00
rodzic 186e463a9e
commit 8d09640b22
14 zmienionych plików z 935 dodań i 234 usunięć

Wyświetl plik

@ -14,6 +14,13 @@
#if MICROPY_HW_HAS_MMA7660
/// \moduleref pyb
/// \class Accel - accelerometer control
///
/// Accel is an object that controls the accelerometer.
///
/// Raw values are between -30 and 30.
#define MMA_ADDR (0x98)
#define MMA_REG_X (0)
#define MMA_REG_Y (1)
@ -83,6 +90,8 @@ typedef struct _pyb_accel_obj_t {
STATIC pyb_accel_obj_t pyb_accel_obj;
/// \classmethod \constructor()
/// Create and return an accelerometer object.
STATIC mp_obj_t pyb_accel_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
@ -100,32 +109,38 @@ STATIC mp_obj_t read_axis(int axis) {
return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0]));
}
/// \method x()
/// Get the x-axis value.
STATIC mp_obj_t pyb_accel_x(mp_obj_t self_in) {
return read_axis(MMA_REG_X);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_x_obj, pyb_accel_x);
/// \method y()
/// Get the y-axis value.
STATIC mp_obj_t pyb_accel_y(mp_obj_t self_in) {
return read_axis(MMA_REG_Y);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_y_obj, pyb_accel_y);
/// \method z()
/// Get the z-axis value.
STATIC mp_obj_t pyb_accel_z(mp_obj_t self_in) {
return read_axis(MMA_REG_Z);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z);
/// \method tilt()
/// Get the tilt register.
STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) {
uint8_t data[1];
HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
return mp_obj_new_int(data[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt);
/// \method filtered_xyz()
/// Get a 3-tuple of filtered x, y and z values.
STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) {
pyb_accel_obj_t *self = self_in;
@ -146,7 +161,6 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) {
return mp_obj_new_tuple(3, tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_xyz);
STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) {
@ -154,7 +168,6 @@ STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) {
HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200);
return mp_obj_new_int(data[0]);
}
MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read);
STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) {
@ -163,7 +176,6 @@ STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) {
HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write);
STATIC const mp_map_elem_t pyb_accel_locals_dict_table[] = {

Wyświetl plik

@ -14,16 +14,19 @@
#include "genhdr/pins.h"
#include "timer.h"
// Usage Model:
//
// adc = pyb.ADC(pin)
// val = adc.read()
//
// adc = pyb.ADCAll(resolution)
// val = adc.read_channel(channel)
// val = adc.read_core_temp()
// val = adc.read_core_vbat()
// val = adc.read_core_vref()
/// \moduleref pyb
/// \class ADC - analog to digital conversion: read analog values on a pin
///
/// Usage:
///
/// adc = pyb.ADC(pin) # create an analog object from a pin
/// val = adc.read() # read an analog value
///
/// adc = pyb.ADCAll(resolution) # creale an ADCAll object
/// val = adc.read_channel(channel) # read the given channel
/// val = adc.read_core_temp() # read MCU temperature
/// val = adc.read_core_vbat() # read MCU VBAT
/// val = adc.read_core_vref() # read MCU VREF
/* ADC defintions */
#define ADCx (ADC1)
@ -118,6 +121,9 @@ STATIC void adc_print(void (*print)(void *env, const char *fmt, ...), void *env,
print(env, " channel=%lu>", self->channel);
}
/// \classmethod \constructor(pin)
/// Create an ADC object associated with the given pin.
/// This allows you to then read analog values on that pin.
STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check number of arguments
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -155,15 +161,30 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
return o;
}
/// \method read()
/// Read the value on the analog pin and return it. The returned value
/// will be between 0 and 4095.
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
uint32_t data = adc_read_channel(&self->handle);
return mp_obj_new_int(data);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
/// \method read_timed(buf, freq)
/// Read analog values into the given buffer at the given frequency.
///
/// Example:
///
/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
/// buf = bytearray(100) # create a buffer of 100 bytes
/// adc.read_timed(buf, 10) # read analog values into buf at 10Hz
/// # this will take 10 seconds to finish
/// for val in buf: # loop over all values
/// print(val) # print the value out
///
/// This function does not allocate any memory.
STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
pyb_obj_adc_t *self = self_in;
@ -196,7 +217,6 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
return mp_obj_new_int(bufinfo.len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
STATIC const mp_map_elem_t adc_locals_dict_table[] = {

Wyświetl plik

@ -13,6 +13,10 @@
#include "timer.h"
#include "dac.h"
/// \moduleref pyb
/// \class DAC - digital to analog conversion
///
STATIC DAC_HandleTypeDef DAC_Handle;
void dac_init(void) {

Wyświetl plik

@ -15,58 +15,52 @@
#include "pin.h"
#include "extint.h"
// Usage Model:
//
// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
// and the remaining 6 are from internal sources.
//
// For lines 0 thru 15, a given line can map to the corresponding line from an
// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
// line 1 can map to Px1 where x is A, B, C, ...
//
// def callback(line):
// print("line =", line)
//
// # Note: ExtInt will automatically configure the gpio line as an input.
// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.GPIO.PULL_UP, callback)
//
// Now every time a falling edge is seen on the X1 pin, the callback will be
// called. Caution: mechanical pushbuttons have "bounce" and pushing or
// releasing a switch will often generate multiple edges.
// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
// explanation, along with various techniques for debouncing.
//
// Trying to register 2 callbacks onto the same pin will throw an exception.
//
// If pin is passed as an integer, then it is assumed to map to one of the
// internal interrupt sources, and must be in the range 16 thru 22.
//
// All other pin objects go through the pin mapper to come up with one of the
// gpio pins.
//
// extint = pyb.ExtInt(pin, mode, pull, callback)
//
// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING,
// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING,
// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING.
//
// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have
// something to do with sleep mode and the WFE instruction.
//
// Valid pull values are pyb.GPIO.PULL_UP, pyb.GPIO.PULL_DOWN, pyb.GPIO.PULL_NONE.
//
// extint.line() will return the line number that pin was mapped to.
// extint.disable() can be use to disable the interrupt associated with a given
// exti object. This could be useful for debouncing.
// extint.enable() enables a disabled interrupt
// extint.swint() will allow the callback to be triggered from software.
//
// pyb.ExtInt.regs() will dump the values of the EXTI registers.
//
// There is also a C API, so that drivers which require EXTI interrupt lines
// can also use this code. See extint.h for the available functions and
// usrsw.h for an example of using this.
//
/// \moduleref pyb
/// \class ExtInt - configure I/O pins to interrupt on external events
///
/// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
/// and the remaining 6 are from internal sources.
///
/// For lines 0 thru 15, a given line can map to the corresponding line from an
/// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
/// line 1 can map to Px1 where x is A, B, C, ...
///
/// def callback(line):
/// print("line =", line)
///
/// Note: ExtInt will automatically configure the gpio line as an input.
///
/// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.GPIO.PULL_UP, callback)
///
/// Now every time a falling edge is seen on the X1 pin, the callback will be
/// called. Caution: mechanical pushbuttons have "bounce" and pushing or
/// releasing a switch will often generate multiple edges.
/// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
/// explanation, along with various techniques for debouncing.
///
/// Trying to register 2 callbacks onto the same pin will throw an exception.
///
/// If pin is passed as an integer, then it is assumed to map to one of the
/// internal interrupt sources, and must be in the range 16 thru 22.
///
/// All other pin objects go through the pin mapper to come up with one of the
/// gpio pins.
///
/// extint = pyb.ExtInt(pin, mode, pull, callback)
///
/// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING,
/// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING,
/// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING.
///
/// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have
/// something to do with sleep mode and the WFE instruction.
///
/// Valid pull values are pyb.GPIO.PULL_UP, pyb.GPIO.PULL_DOWN, pyb.GPIO.PULL_NONE.
///
/// There is also a C API, so that drivers which require EXTI interrupt lines
/// can also use this code. See extint.h for the available functions and
/// usrsw.h for an example of using this.
// TODO Add python method to change callback object.
#define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE)
@ -204,29 +198,45 @@ void extint_swint(uint line) {
EXTI->SWIER = (1 << line);
}
/// \method line()
/// Return the line number that the pin is mapped to.
STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) {
extint_obj_t *self = self_in;
return MP_OBJ_NEW_SMALL_INT(self->line);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj,i extint_obj_line);
/// \method enable()
/// Enable a disabled interrupt.
STATIC mp_obj_t extint_obj_enable(mp_obj_t self_in) {
extint_obj_t *self = self_in;
extint_enable(self->line);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable);
/// \method disable()
/// Disable the interrupt associated with the ExtInt object.
/// This could be useful for debouncing.
STATIC mp_obj_t extint_obj_disable(mp_obj_t self_in) {
extint_obj_t *self = self_in;
extint_disable(self->line);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable);
/// \method swint()
/// Trigger the callback from software.
STATIC mp_obj_t extint_obj_swint(mp_obj_t self_in) {
extint_obj_t *self = self_in;
extint_swint(self->line);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint);
// TODO document as a staticmethod
/// \classmethod regs()
/// Dump the values of the EXTI registers.
STATIC mp_obj_t extint_regs(void) {
printf("EXTI_IMR %08lx\n", EXTI->IMR);
printf("EXTI_EMR %08lx\n", EXTI->EMR);
@ -236,9 +246,24 @@ STATIC mp_obj_t extint_regs(void) {
printf("EXTI_PR %08lx\n", EXTI->PR);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj);
// line_obj = pyb.ExtInt(pin, mode, pull, callback)
/// \classmethod \constructor(pin, mode, pull, callback)
/// Create an ExtInt object:
///
/// - `pin` is the pin on which to enable the interrupt (can be a pin object or any valid pin name).
/// - `mode` can be one of:
/// - `ExtInt.IRQ_RISING` - trigger on a rising edge;
/// - `ExtInt.IRQ_FALLING` - trigger on a falling edge;
/// - `ExtInt.IRQ_RISING_FALLING` - trigger on a rising or falling edge.
/// - `pull` can be one of:
/// - `pyb.Pin.PULL_NONE` - no pull up or down resistors;
/// - `pyb.Pin.PULL_UP` - enable the pull-up resistor;
/// - `pyb.Pin.PULL_DOWN` - enable the pull-down resistor.
/// - `callback` is the function to call when the interrupt triggers. The
/// callback function must accept exactly 1 argument, which is the line that
/// triggered the interrupt.
STATIC const mp_arg_t pyb_extint_make_new_args[] = {
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@ -268,19 +293,17 @@ STATIC void extint_obj_print(void (*print)(void *env, const char *fmt, ...), voi
print(env, "<ExtInt line=%u>", self->line);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj, extint_obj_line);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj);
STATIC const mp_map_elem_t extint_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_line), (mp_obj_t)&extint_obj_line_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&extint_obj_enable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&extint_obj_disable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_swint), (mp_obj_t)&extint_obj_swint_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_regs), (mp_obj_t)&extint_regs_obj },
// class constants
/// \constant IRQ_RISING - interrupt on a rising edge
/// \constant IRQ_FALLING - interrupt on a falling edge
/// \constant IRQ_RISING_FALLING - interrupt on a rising or falling edge
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_FALLING) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING_FALLING) },

356
stmhal/gendoc.py 100644
Wyświetl plik

@ -0,0 +1,356 @@
"""
Generate documentation for pyboard API from C files.
"""
import os
import argparse
import re
import markdown
# given a list of (name,regex) pairs, find the first one that matches the given line
def re_match_first(regexs, line):
for name, regex in regexs:
match = re.match(regex, line)
if match:
return name, match
return None, None
def makedirs(d):
if not os.path.isdir(d):
os.makedirs(d)
class Lexer:
class LexerError(Exception):
pass
class EOF(Exception):
pass
class Break(Exception):
pass
def __init__(self, file):
self.filename = file
with open(file, 'rt') as f:
line_num = 0
lines = []
for line in f:
line_num += 1
line = line.strip()
if line == '///':
lines.append((line_num, ''))
elif line.startswith('/// '):
lines.append((line_num, line[4:]))
elif len(lines) > 0 and lines[-1][1] is not None:
lines.append((line_num, None))
if len(lines) > 0 and lines[-1][1] is not None:
lines.append((line_num, None))
self.cur_line = 0
self.lines = lines
def opt_break(self):
if len(self.lines) > 0 and self.lines[0][1] is None:
self.lines.pop(0)
def next(self):
if len(self.lines) == 0:
raise Lexer.EOF
else:
l = self.lines.pop(0)
self.cur_line = l[0]
if l[1] is None:
raise Lexer.Break
else:
return l[1]
def error(self, msg):
print('({}:{}) {}'.format(self.filename, self.cur_line, msg))
raise Lexer.LexerError
class DocItem:
def __init__(self):
self.doc = []
def add_doc(self, lex):
try:
while True:
line = lex.next()
if len(line) > 0 or len(self.doc) > 0:
self.doc.append(line)
except Lexer.Break:
pass
def dump(self):
return '\n'.join(self.doc)
class DocConstant(DocItem):
def __init__(self, name, descr):
super().__init__()
self.name = name
self.descr = descr
def dump(self, ctx):
return '{}.{} - {}'.format(ctx, self.name, self.descr)
class DocFunction(DocItem):
def __init__(self, name, args):
super().__init__()
self.name = name
self.args = args
def dump(self, ctx):
if self.name == '\\constructor':
s = '### `{}{}`'.format(ctx, self.args)
elif self.name == '\\call':
s = '### `{}{}`'.format(ctx, self.args)
else:
s = '### `{}.{}{}`'.format(ctx, self.name, self.args)
return s + '\n' + super().dump()
class DocClass(DocItem):
def __init__(self, name, descr):
super().__init__()
self.name = name
self.descr = descr
self.constructors = {}
self.classmethods = {}
self.methods = {}
self.constants = {}
def process_classmethod(self, lex, d):
name = d['id']
if name == '\\constructor':
dict_ = self.constructors
else:
dict_ = self.classmethods
if name in dict_:
lex.error("multiple definition of method '{}'".format(name))
method = dict_[name] = DocFunction(name, d['args'])
method.add_doc(lex)
def process_method(self, lex, d):
name = d['id']
dict_ = self.methods
if name in dict_:
lex.error("multiple definition of method '{}'".format(name))
method = dict_[name] = DocFunction(name, d['args'])
method.add_doc(lex)
def process_constant(self, lex, d):
name = d['id']
if name in self.constants:
lex.error("multiple definition of constant '{}'".format(name))
self.constants[name] = DocConstant(name, d['descr'])
lex.opt_break()
def dump(self):
s = []
s.append('')
s.append('# class {}'.format(self.name))
s.append('')
s.append(super().dump())
if len(self.constructors) > 0:
s.append('')
s.append("## Constructors")
for f in sorted(self.constructors.values(), key=lambda x:x.name):
s.append('')
s.append(f.dump(self.name))
if len(self.classmethods) > 0:
s.append('')
s.append("## Class methods")
for f in sorted(self.classmethods.values(), key=lambda x:x.name):
s.append('')
s.append(f.dump(self.name))
if len(self.methods) > 0:
s.append('')
s.append("## Methods")
for f in sorted(self.methods.values(), key=lambda x:x.name):
s.append('')
s.append(f.dump(self.name.lower()))
if len(self.constants) > 0:
s.append('')
s.append("## Constants")
for c in sorted(self.constants.values(), key=lambda x:x.name):
s.append('')
s.append('`{}`'.format(c.dump(self.name)))
return '\n'.join(s)
class DocModule(DocItem):
def __init__(self, name, descr):
super().__init__()
self.name = name
self.descr = descr
self.functions = {}
self.constants = {}
self.classes = {}
self.cur_class = None
def new_file(self):
self.cur_class = None
def process_function(self, lex, d):
name = d['id']
if name in self.functions:
lex.error("multiple definition of function '{}'".format(name))
function = self.functions[name] = DocFunction(name, d['args'])
function.add_doc(lex)
#def process_classref(self, lex, d):
# name = d['id']
# self.classes[name] = name
# lex.opt_break()
def process_class(self, lex, d):
name = d['id']
if name in self.classes:
lex.error("multiple definition of class '{}'".format(name))
self.cur_class = self.classes[name] = DocClass(name, d['descr'])
self.cur_class.add_doc(lex)
def process_classmethod(self, lex, d):
self.cur_class.process_classmethod(lex, d)
def process_method(self, lex, d):
self.cur_class.process_method(lex, d)
def process_constant(self, lex, d):
self.cur_class.process_constant(lex, d)
def dump(self):
s = []
s.append('# module {}'.format(self.name))
s.append('')
s.append(super().dump())
s.append('')
s.append('## Functions')
for f in sorted(self.functions.values(), key=lambda x:x.name):
s.append('')
s.append(f.dump(self.name))
s.append('')
s.append('## Classes')
for c in sorted(self.classes.values(), key=lambda x:x.name):
s.append('')
s.append('[`{}.{}`]({}/index.html) - {}'.format(self.name, c.name, c.name, c.descr))
return '\n'.join(s)
def write(self, dir):
index = markdown.markdown(self.dump())
with open(os.path.join(dir, 'index.html'), 'wt') as f:
f.write(index)
for c in self.classes.values():
class_dir = os.path.join(dir, c.name)
makedirs(class_dir)
class_dump = c.dump()
class_dump = 'part of the [{} module](../index.html)'.format(self.name) + '\n' + class_dump
index = markdown.markdown(class_dump)
with open(os.path.join(class_dir, 'index.html'), 'wt') as f:
f.write(index)
class Doc:
def __init__(self):
self.modules = {}
self.cur_module = None
def new_file(self):
self.cur_module = None
for m in self.modules.values():
m.new_file()
def check_module(self, lex):
if self.cur_module is None:
lex.error('module not defined')
def process_module(self, lex, d):
name = d['id']
if name in self.modules:
lex.error("multiple definition of module '{}'".format(name))
self.cur_module = self.modules[name] = DocModule(name, d['descr'])
self.cur_module.add_doc(lex)
def process_moduleref(self, lex, d):
name = d['id']
if name not in self.modules:
lex.error('module {} referenced before definition'.format(name))
self.cur_module = self.modules[name]
#def process_classref(self, lex, d):
# self.cur_module.process_classref(lex, d)
def process_class(self, lex, d):
self.check_module(lex)
self.cur_module.process_class(lex, d)
def process_function(self, lex, d):
self.check_module(lex)
self.cur_module.process_function(lex, d)
def process_classmethod(self, lex, d):
self.check_module(lex)
self.cur_module.process_classmethod(lex, d)
def process_method(self, lex, d):
self.check_module(lex)
self.cur_module.process_method(lex, d)
def process_constant(self, lex, d):
self.check_module(lex)
self.cur_module.process_constant(lex, d)
def write(self, dir):
for m in self.modules.values():
mod_dir = os.path.join(dir, 'module', m.name)
makedirs(mod_dir)
m.write(mod_dir)
regex_descr = r'(?P<descr>.*)'
doc_regexs = (
(Doc.process_module, re.compile(r'\\module (?P<id>[a-z]+) - ' + regex_descr + r'$')),
(Doc.process_moduleref, re.compile(r'\\moduleref (?P<id>[a-z]+)$')),
(Doc.process_function, re.compile(r'\\function (?P<id>[a-z0-9_]+)(?P<args>\(.*\))$')),
(Doc.process_classmethod, re.compile(r'\\classmethod (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$')),
(Doc.process_method, re.compile(r'\\method (?P<id>\\?[a-z0-9_]+)(?P<args>\(.*\))$')),
(Doc.process_constant, re.compile(r'\\constant (?P<id>[A-Z0-9_]+) - ' + regex_descr + r'$')),
#(Doc.process_classref, re.compile(r'\\classref (?P<id>[A-Za-z0-9_]+)$')),
(Doc.process_class, re.compile(r'\\class (?P<id>[A-Za-z0-9_]+) - ' + regex_descr + r'$')),
)
def process_file(file, doc):
lex = Lexer(file)
doc.new_file()
try:
try:
while True:
line = lex.next()
fun, match = re_match_first(doc_regexs, line)
if fun == None:
lex.error('unknown line format: {}'.format(line))
fun(doc, lex, match.groupdict())
except Lexer.Break:
lex.error('unexpected break')
except Lexer.EOF:
pass
except Lexer.LexerError:
return False
return True
def main():
cmd_parser = argparse.ArgumentParser(description='Generate documentation for pyboard API from C files.')
cmd_parser.add_argument('--outdir', metavar='<output dir>', default='gendoc-out', help='ouput directory')
cmd_parser.add_argument('files', nargs='+', help='input files')
args = cmd_parser.parse_args()
doc = Doc()
for file in args.files:
print('processing', file)
if not process_file(file, doc):
return
doc.write(args.outdir)
print('written to', args.outdir)
if __name__ == "__main__":
main()

Wyświetl plik

@ -14,50 +14,54 @@
#include "bufhelper.h"
#include "i2c.h"
// Usage model:
//
// I2C objects are created attached to a specific bus. They can be initialised
// when created, or initialised later on:
//
// from pyb import I2C
//
// i2c = I2C(1) # create on bus 1
// i2c = I2C(1, I2C.MASTER) # create and init as a master
// i2c.deinit() # turn off the peripheral
// i2c.init(I2C.MASTER, baudrate=20000) # init as a master
// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
//
// Printing the i2c object gives you information about its configuration.
//
// Basic methods for slave are send and recv:
//
// i2c.send('abc') # send 3 bytes
// i2c.send(0x42) # send a single byte, given by the number
// data = i2c.recv(3) # receive 3 bytes
//
// To receive inplace, first create a bytearray:
//
// data = bytearray(3) # create a buffer
// i2c.recv(data) # receive 3 bytes, writing them into data
//
// You can specify a timeout (in ms):
//
// i2c.send(b'123', timeout=2000) # timout after 2 seconds
//
// A master must specify the recipient's address:
//
// i2c.init(I2C.MASTER)
// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
// i2c.send(b'456', addr=0x42) # keyword for address
//
// Master also has other methods:
//
// i2c.is_ready(0x42) # check if slave 0x42 is ready
// i2c.scan() # scan for slaves on the bus, returning
// # a list of valid addresses
// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
// # starting at address 2 in the slave
// i2c.mem_write('abc', 0x42, 2, timeout=1000)
/// \moduleref pyb
/// \class I2C - a two-wire serial protocol
///
/// I2C is a two-wire protocol for communicating between devices. At the physical
/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
///
/// I2C objects are created attached to a specific bus. They can be initialised
/// when created, or initialised later on:
///
/// from pyb import I2C
///
/// i2c = I2C(1) # create on bus 1
/// i2c = I2C(1, I2C.MASTER) # create and init as a master
/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master
/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
/// i2c.deinit() # turn off the peripheral
///
/// Printing the i2c object gives you information about its configuration.
///
/// Basic methods for slave are send and recv:
///
/// i2c.send('abc') # send 3 bytes
/// i2c.send(0x42) # send a single byte, given by the number
/// data = i2c.recv(3) # receive 3 bytes
///
/// To receive inplace, first create a bytearray:
///
/// data = bytearray(3) # create a buffer
/// i2c.recv(data) # receive 3 bytes, writing them into data
///
/// You can specify a timeout (in ms):
///
/// i2c.send(b'123', timeout=2000) # timout after 2 seconds
///
/// A master must specify the recipient's address:
///
/// i2c.init(I2C.MASTER)
/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
/// i2c.send(b'456', addr=0x42) # keyword for address
///
/// Master also has other methods:
///
/// i2c.is_ready(0x42) # check if slave 0x42 is ready
/// i2c.scan() # scan for slaves on the bus, returning
/// # a list of valid addresses
/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
/// # starting at address 2 in the slave
/// i2c.mem_write('abc', 0x42, 2, timeout=1000)
#define PYB_I2C_MASTER (0)
#define PYB_I2C_SLAVE (1)
@ -176,6 +180,14 @@ STATIC void pyb_i2c_print(void (*print)(void *env, const char *fmt, ...), void *
}
}
/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False)
///
/// Initialise the I2C bus with the given parameters:
///
/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE`
/// - `addr` is the 7-bit address (only sensible for a slave)
/// - `baudrate` is the SCL clock rate (only sensible for a master)
/// - `gencall` is whether to support general call mode
STATIC const mp_arg_t pyb_i2c_init_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} },
@ -213,6 +225,13 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, uint n_args, cons
return mp_const_none;
}
/// \classmethod \constructor(bus, ...)
///
/// Construct an I2C object on the given bus. `bus` can be 1 or 2.
/// With no additional parameters, the I2C object is created but not
/// initialised (it has the settings from the last initialisation of
/// the bus, if any). If extra arguments are given, the bus is initialised.
/// See `init` for parameters of initialisation.
STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
@ -243,6 +262,8 @@ STATIC mp_obj_t pyb_i2c_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
/// \method deinit()
/// Turn off the I2C bus.
STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
pyb_i2c_obj_t *self = self_in;
i2c_deinit(self->i2c);
@ -250,7 +271,8 @@ STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
// Check if an I2C device responds to the given address.
/// \method is_ready(addr)
/// Check if an I2C device responds to the given address. Only valid when in master mode.
STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
pyb_i2c_obj_t *self = self_in;
@ -271,7 +293,9 @@ STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
/// \method scan()
/// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
/// Only valid when in master mode.
STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
pyb_i2c_obj_t *self = self_in;
@ -295,6 +319,14 @@ STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
/// \method send(send, addr=0x00, timeout=5000)
/// Send data on the bus:
///
/// - `send` is the data to send (an integer to send, or a buffer object)
/// - `addr` is the address to send to (only required in master mode)
/// - `timeout` is the timeout in milliseconds to wait for the send
///
/// Return value: `None`.
STATIC const mp_arg_t pyb_i2c_send_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
@ -335,6 +367,17 @@ STATIC mp_obj_t pyb_i2c_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send);
/// \method recv(send, addr=0x00, timeout=5000)
///
/// Receive data on the bus:
///
/// - `recv` can be an integer, which is the number of bytes to receive,
/// or a mutable buffer, which will be filled with received bytes
/// - `addr` is the address to receive from (only required in master mode)
/// - `timeout` is the timeout in milliseconds to wait for the receive
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
/// otherwise the same buffer that was passed in to `recv`.
STATIC const mp_arg_t pyb_i2c_recv_args[] = {
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} },
@ -379,6 +422,17 @@ STATIC mp_obj_t pyb_i2c_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv);
/// \method mem_read(data, addr, memaddr, timeout=5000)
///
/// Read from the memory of an I2C device:
///
/// - `data` can be an integer or a buffer to read into
/// - `addr` is the I2C device address
/// - `memaddr` is the memory location within the I2C device
/// - `timeout` is the timeout in milliseconds to wait for the read
///
/// Returns the read data.
/// This is only valid in master mode.
STATIC const mp_arg_t pyb_i2c_mem_read_args[] = {
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@ -422,6 +476,17 @@ STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args, mp_map_t *kw
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read);
/// \method mem_write(data, addr, memaddr, timeout=5000)
///
/// Write to the memory of an I2C device:
///
/// - `data` can be an integer or a buffer to write from
/// - `addr` is the I2C device address
/// - `memaddr` is the memory location within the I2C device
/// - `timeout` is the timeout in milliseconds to wait for the write
///
/// Returns `None`.
/// This is only valid in master mode.
STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_i2c_obj_t *self = args[0];
@ -465,6 +530,8 @@ STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
// class constants
/// \constant MASTER - for initialising the bus to master mode
/// \constant SLAVE - for initialising the bus to slave mode
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYB_I2C_MASTER) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(PYB_I2C_SLAVE) },
};

Wyświetl plik

@ -12,6 +12,11 @@
#include "pin.h"
#include "genhdr/pins.h"
/// \moduleref pyb
/// \class LED - LED object
///
/// The LED object controls an individual LED (Light Emitting Diode).
typedef struct _pyb_led_obj_t {
mp_obj_base_t base;
machine_uint_t led_id;
@ -195,6 +200,10 @@ void led_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp
print(env, "<LED %lu>", self->led_id);
}
/// \classmethod \constructor(id)
/// Create an LED object associated with the given LED:
///
/// - `id` is the LED number, 1-4.
STATIC mp_obj_t led_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -211,24 +220,34 @@ STATIC mp_obj_t led_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
return (mp_obj_t)&pyb_led_obj[led_id];
}
/// \method on()
/// Turn the LED on.
mp_obj_t led_obj_on(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_state(self->led_id, 1);
return mp_const_none;
}
/// \method off()
/// Turn the LED off.
mp_obj_t led_obj_off(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_state(self->led_id, 0);
return mp_const_none;
}
/// \method toggle()
/// Toggle the LED between on and off.
mp_obj_t led_obj_toggle(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_toggle(self->led_id);
return mp_const_none;
}
/// \method intensity([value])
/// Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on).
/// If no argument is given, return the LED intensity.
/// If an argument is given, set the LED intensity and return `None`.
mp_obj_t led_obj_intensity(uint n_args, const mp_obj_t *args) {
pyb_led_obj_t *self = args[0];
if (n_args == 1) {

Wyświetl plik

@ -32,7 +32,12 @@
#include "modpyb.h"
#include "ff.h"
// print lots of info about the board
/// \module pyb - functions related to the pyboard
///
/// The `pyb` module contains specific functions related to the pyboard.
/// \function info([dump_alloc_table])
/// Print out lots of information about the board.
STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
// get and print unique id; 96 bits
{
@ -99,14 +104,16 @@ STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
// get unique MCU id; 96 bits = 12 bytes
/// \function unique_id()
/// Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU.
STATIC mp_obj_t pyb_unique_id(void) {
byte *id = (byte*)0x1fff7a10;
return mp_obj_new_bytes(id, 12);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
// get clock frequencies
/// \function freq()
/// Return a tuple of clock frequencies: (SYSCLK, HCLK, PCLK1, PCLK2).
// TODO should also be able to set frequency via this function
STATIC mp_obj_t pyb_freq(void) {
mp_obj_t tuple[4] = {
@ -119,24 +126,31 @@ STATIC mp_obj_t pyb_freq(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq);
// sync all file systems
/// \function sync()
/// Sync all file systems.
STATIC mp_obj_t pyb_sync(void) {
storage_flush();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync);
/// \function millis()
/// Returns the number of milliseconds since the board was last reset.
STATIC mp_obj_t pyb_millis(void) {
return mp_obj_new_int(HAL_GetTick());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis);
/// \function delay(ms)
/// Delay for the given number of milliseconds.
STATIC mp_obj_t pyb_delay(mp_obj_t count) {
HAL_Delay(mp_obj_get_int(count));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay);
/// \function udelay(us)
/// Delay for the given number of microseconds.
STATIC mp_obj_t pyb_udelay(mp_obj_t usec) {
uint32_t count = 0;
const uint32_t utime = (168 * mp_obj_get_int(usec) / 5);
@ -146,28 +160,32 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec) {
}
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
/// \function wfi()
/// Wait for an interrupt.
/// This executies a `wfi` instruction which reduces power consumption
/// of the MCU until an interrupt occurs, at which point execution continues.
STATIC mp_obj_t pyb_wfi(void) {
__WFI();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi);
/// \function disable_irq()
/// Disable interrupt requests.
STATIC mp_obj_t pyb_disable_irq(void) {
__disable_irq();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq);
/// \function enable_irq()
/// Enable interrupt requests.
STATIC mp_obj_t pyb_enable_irq(void) {
__enable_irq();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_enable_irq_obj, pyb_enable_irq);
#if 0
@ -224,12 +242,16 @@ STATIC mp_obj_t pyb_standby(void) {
MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby);
/// \function have_cdc()
/// Return True if USB is connected as a serial device, False otherwise.
STATIC mp_obj_t pyb_have_cdc(void ) {
return MP_BOOL(usb_vcp_is_connected());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
/// \function hid((buttons, x, y, z))
/// Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
/// signal a HID mouse-motion event.
STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
mp_obj_t *items;
mp_obj_get_array_fixed_n(arg, 4, &items);
@ -241,7 +263,6 @@ STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
usb_hid_send_report(data);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c

Wyświetl plik

@ -12,54 +12,61 @@
#include "runtime.h"
#include "pin.h"
// Usage Model:
//
// All Board Pins are predefined as pyb.Pin.board.Name
//
// x1_pin = pyb.Pin.board.X1
//
// g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
//
// CPU pins which correspond to the board pins are available
// as pyb.cpu.Name. For the CPU pins, the names are the port letter
// followed by the pin number. On the PYBV4, pyb.Pin.board.X1 and
// pyb.Pin.cpu.B6 are the same pin.
//
// You can also use strings:
//
// g = pyb.Pin('X1', pyb.Pin.OUT_PP)
//
// Users can add their own names:
//
// pyb.Pin.dict["LeftMotorDir"] = pyb.Pin.cpu.C12
// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
//
// and can query mappings
//
// pin = pyb.Pin("LeftMotorDir")
//
// Users can also add their own mapping function:
//
// def MyMapper(pin_name):
// if pin_name == "LeftMotorDir":
// return pyb.Pin.cpu.A0
//
// pyb.Pin.mapper(MyMapper)
//
// So, if you were to call: pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)
// then "LeftMotorDir" is passed directly to the mapper function.
//
// To summarize, the following order determines how things get mapped into
// an ordinal pin number:
//
// 1 - Directly specify a pin object
// 2 - User supplied mapping function
// 3 - User supplied mapping (object must be usable as a dictionary key)
// 4 - Supply a string which matches a board pin
// 5 - Supply a string which matches a CPU port/pin
//
// You can set pyb.Pin.debug(True) to get some debug information about
// how a particular object gets mapped to a pin.
/// \moduleref pyb
/// \class Pin - control I/O pins
///
/// A pin is the basic object to control I/O pins. It has methods to set
/// the mode of the pin (input, output, etc) and methods to get and set the
/// digital logic level. For analog control of a pin, see the ADC class.
///
/// Usage Model:
///
/// All Board Pins are predefined as pyb.Pin.board.Name
///
/// x1_pin = pyb.Pin.board.X1
///
/// g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
///
/// CPU pins which correspond to the board pins are available
/// as `pyb.cpu.Name`. For the CPU pins, the names are the port letter
/// followed by the pin number. On the PYBv1.0, `pyb.Pin.board.X1` and
/// `pyb.Pin.cpu.B6` are the same pin.
///
/// You can also use strings:
///
/// g = pyb.Pin('X1', pyb.Pin.OUT_PP)
///
/// Users can add their own names:
///
/// pyb.Pin.dict["LeftMotorDir"] = pyb.Pin.cpu.C12
/// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
///
/// and can query mappings
///
/// pin = pyb.Pin("LeftMotorDir")
///
/// Users can also add their own mapping function:
///
/// def MyMapper(pin_name):
/// if pin_name == "LeftMotorDir":
/// return pyb.Pin.cpu.A0
///
/// pyb.Pin.mapper(MyMapper)
///
/// So, if you were to call: `pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)`
/// then `"LeftMotorDir"` is passed directly to the mapper function.
///
/// To summarise, the following order determines how things get mapped into
/// an ordinal pin number:
///
/// 1. Directly specify a pin object
/// 2. User supplied mapping function
/// 3. User supplied mapping (object must be usable as a dictionary key)
/// 4. Supply a string which matches a board pin
/// 5. Supply a string which matches a CPU port/pin
///
/// You can set `pyb.Pin.debug(True)` to get some debug information about
/// how a particular object gets mapped to a pin.
// Pin class variables
STATIC mp_obj_t pin_class_mapper;
@ -152,6 +159,8 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name));
}
/// \method __str__()
/// Return a string describing the pin object.
STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pin_obj_t *self = self_in;
print(env, "<Pin %s>", self->name);
@ -159,7 +168,9 @@ STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env,
STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args);
// Pin constructor
/// \classmethod \constructor(id, ...)
/// Create a new Pin object associated with the id. If additional arguments are given,
/// they are used to initialise the pin. See `init`.
STATIC mp_obj_t pin_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 3, false);
@ -178,7 +189,8 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_
return (mp_obj_t)pin;
}
// class method
/// \classmethod mapper([fun])
/// Get or set the pin mapper function.
STATIC mp_obj_t pin_mapper(uint n_args, mp_obj_t *args) {
if (n_args > 1) {
pin_class_mapper = args[1];
@ -189,7 +201,8 @@ STATIC mp_obj_t pin_mapper(uint n_args, mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj);
// class method
/// \classmethod dict([dict])
/// Get or set the pin mapper dictionary.
STATIC mp_obj_t pin_map_dict(uint n_args, mp_obj_t *args) {
if (n_args > 1) {
pin_class_map_dict = args[1];
@ -200,7 +213,8 @@ STATIC mp_obj_t pin_map_dict(uint n_args, mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj);
// class method
/// \classmethod debug([state])
/// Get or set the debugging state (`True` or `False` for on or off).
STATIC mp_obj_t pin_debug(uint n_args, mp_obj_t *args) {
if (n_args > 1) {
pin_class_debug = mp_obj_is_true(args[1]);
@ -211,6 +225,22 @@ STATIC mp_obj_t pin_debug(uint n_args, mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj);
/// \method init(mode, pull=Pin.PULL_NONE)
/// Initialise the pin:
///
/// - `mode` can be one of:
/// - `Pin.IN` - configure the pin for input;
/// - `Pin.OUT_PP` - configure the pin for output, with push-pull control;
/// - `Pin.OUT_OD` - configure the pin for output, with open-drain control;
/// - `Pin.AF_PP` - configure the pin for alternate function, pull-pull;
/// - `Pin.AF_OD` - configure the pin for alternate function, open-drain;
/// - `Pin.ANALOG` - configure the pin for analog.
/// - `pull` can be one of:
/// - `Pin.PULL_NONE` - no pull up or down resistors;
/// - `Pin.PULL_UP` - enable the pull-up resistor;
/// - `Pin.PULL_DOWN` - enable the pull-down resistor.
///
/// Returns: `None`.
STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args) {
pin_obj_t *self = args[0];
@ -242,6 +272,13 @@ STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_init_obj, 2, 3, pin_obj_init);
/// \method value([value])
/// Get or set the digital logic level of the pin:
///
/// - With no argument, return 0 or 1 depending on the logic level of the pin.
/// - With `value` given, set the logic level of the pin. `value` can be
/// anything that converts to a boolean. If it converts to `True`, the pin
/// is set high, otherwise it is set low.
STATIC mp_obj_t pin_value(uint n_args, mp_obj_t *args) {
pin_obj_t *self = args[0];
if (n_args == 1) {
@ -259,6 +296,8 @@ STATIC mp_obj_t pin_value(uint n_args, mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value);
/// \method low()
/// Set the pin to a low logic level.
STATIC mp_obj_t pin_low(mp_obj_t self_in) {
pin_obj_t *self = self_in;
self->gpio->BSRRH = self->pin_mask;
@ -266,6 +305,8 @@ STATIC mp_obj_t pin_low(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low);
/// \method high()
/// Set the pin to a high logic level.
STATIC mp_obj_t pin_high(mp_obj_t self_in) {
pin_obj_t *self = self_in;
self->gpio->BSRRL = self->pin_mask;
@ -273,18 +314,24 @@ STATIC mp_obj_t pin_high(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high);
/// \method name()
/// Get the pin name.
STATIC mp_obj_t pin_name(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_QSTR(qstr_from_str(self->name));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name);
/// \method port()
/// Get the pin port.
STATIC mp_obj_t pin_port(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->port);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port);
/// \method pin()
/// Get the pin number.
STATIC mp_obj_t pin_pin(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->pin);
@ -311,6 +358,12 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_cpu), (mp_obj_t)&pin_cpu_pins_obj },
// class constants
/// \constant IN - initialise the pin to input mode
/// \constant OUT_PP - initialise the pin to output mode with a push-pull drive
/// \constant OUT_OD - initialise the pin to output mode with an open-drain drive
/// \constant PULL_NONE - don't enable any pull up or down resistors on the pin
/// \constant PULL_UP - enable the pull-up resistor on the pin
/// \constant PULL_DOWN - enable the pull-down resistor on the pin
{ MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_INPUT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OUT_PP), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_PP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OUT_OD), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_OD) },

Wyświetl plik

@ -10,6 +10,8 @@
#if MICROPY_HW_ENABLE_RNG
/// \moduleref pyb
STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL};
void rng_init0(void) {
@ -30,6 +32,8 @@ uint32_t rng_get(void) {
return HAL_RNG_GetRandomNumber(&RNGHandle);
}
/// \function rng()
/// Return a 30-bit hardware generated random number.
STATIC mp_obj_t pyb_rng_get(void) {
if (RNGHandle.State == HAL_RNG_STATE_RESET) {
rng_init();

Wyświetl plik

@ -11,6 +11,11 @@
#include "timer.h"
#include "servo.h"
/// \moduleref pyb
/// \class Servo - 3-wire hobby servo driver
///
/// Servo controls standard hobby servos with 3-wires (ground, power, signal).
// this servo driver uses hardware PWM to drive servos on PA0, PA1, PA2, PA3 = X1, X2, X3, X4
// TIM2 and TIM5 have CH1, CH2, CH3, CH4 on PA0-PA3 respectively
// they are both 32-bit counters with 16-bit prescaler
@ -156,6 +161,8 @@ STATIC void pyb_servo_print(void (*print)(void *env, const char *fmt, ...), void
print(env, "<Servo %lu at %luus>", self->servo_id, 10 * self->pulse_cur);
}
/// \classmethod \constructor(id)
/// Create a servo object. `id` is 1-4.
STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -177,6 +184,8 @@ STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
return s;
}
/// \method pulse_width([value])
/// Get or set the pulse width in milliseconds.
STATIC mp_obj_t pyb_servo_pulse_width(uint n_args, const mp_obj_t *args) {
pyb_servo_obj_t *self = args[0];
if (n_args == 1) {
@ -190,9 +199,10 @@ STATIC mp_obj_t pyb_servo_pulse_width(uint n_args, const mp_obj_t *args) {
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_pulse_width_obj, 1, 2, pyb_servo_pulse_width);
/// \method calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
/// Get or set the calibration of the servo timing.
STATIC mp_obj_t pyb_servo_calibration(uint n_args, const mp_obj_t *args) {
pyb_servo_obj_t *self = args[0];
if (n_args == 1) {
@ -221,9 +231,13 @@ STATIC mp_obj_t pyb_servo_calibration(uint n_args, const mp_obj_t *args) {
// bad number of arguments
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "calibration expecting 1, 4 or 6 arguments, got %d", n_args));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_calibration_obj, 1, 6, pyb_servo_calibration);
/// \method angle([angle, time=0])
/// Get or set the angle of the servo.
///
/// - `angle` is the angle to move to in degrees.
/// - `time` is the number of milliseconds to take to get to the specified angle.
STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) {
pyb_servo_obj_t *self = args[0];
if (n_args == 1) {
@ -247,9 +261,13 @@ STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) {
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle);
/// \method speed([speed, time=0])
/// Get or set the speed of a continuous rotation servo.
///
/// - `speed` is the speed to move to change to, between -100 and 100.
/// - `time` is the number of milliseconds to take to get to the specified speed.
STATIC mp_obj_t pyb_servo_speed(uint n_args, const mp_obj_t *args) {
pyb_servo_obj_t *self = args[0];
if (n_args == 1) {

Wyświetl plik

@ -14,24 +14,28 @@
#include "bufhelper.h"
#include "spi.h"
// Usage model:
//
// See usage model of I2C in i2c.c. SPI is very similar. Main difference is
// parameters to init the SPI bus:
//
// from pyb import SPI
// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=1, crc=0x7)
//
// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
// 0 or 1, and is the level the idle clock line sits at. Phase can be 1 or 2
// for number of edges. Crc can be None for no CRC, or a polynomial specifier.
//
// Additional method for SPI:
//
// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
// buf = bytearray(4)
// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
/// \moduleref pyb
/// \class SPI - a master-driven serial protocol
///
/// SPI is a serial protocol that is driven by a master. At the physical level
/// there are 3 lines: SCK, MOSI, MISO.
///
/// See usage model of I2C; SPI is very similar. Main difference is
/// parameters to init the SPI bus:
///
/// from pyb import SPI
/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=1, crc=0x7)
///
/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
/// 0 or 1, and is the level the idle clock line sits at. Phase can be 1 or 2
/// for number of edges. Crc can be None for no CRC, or a polynomial specifier.
///
/// Additional method for SPI:
///
/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
/// buf = bytearray(4)
/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
#if MICROPY_HW_ENABLE_SPI1
SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL};
@ -194,6 +198,12 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *
}
}
/// \method init(mode, baudrate=328125, *, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=false, crc=None)
///
/// Initialise the SPI bus with the given parameters:
///
/// - `mode` must be either `SPI.MASTER` or `SPI.SLAVE`.
/// - `baudrate` is the SCK clock rate (only sensible for a master).
STATIC const mp_arg_t pyb_spi_init_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} },
@ -258,6 +268,13 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, cons
return mp_const_none;
}
/// \classmethod \constructor(bus, ...)
///
/// Construct an SPI object on the given bus. `bus` can be 1 or 2.
/// With no additional parameters, the SPI object is created but not
/// initialised (it has the settings from the last initialisation of
/// the bus, if any). If extra arguments are given, the bus is initialised.
/// See `init` for parameters of initialisation.
STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
@ -288,6 +305,8 @@ STATIC mp_obj_t pyb_spi_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
/// \method deinit()
/// Turn off the SPI bus.
STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
pyb_spi_obj_t *self = self_in;
spi_deinit(self->spi);
@ -295,6 +314,13 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
/// \method send(send, *, timeout=5000)
/// Send data on the bus:
///
/// - `send` is the data to send (an integer to send, or a buffer object).
/// - `timeout` is the timeout in milliseconds to wait for the send.
///
/// Return value: `None`.
STATIC const mp_arg_t pyb_spi_send_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
@ -327,6 +353,16 @@ STATIC mp_obj_t pyb_spi_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send);
/// \method recv(recv, *, timeout=5000)
///
/// Receive data on the bus:
///
/// - `recv` can be an integer, which is the number of bytes to receive,
/// or a mutable buffer, which will be filled with received bytes.
/// - `timeout` is the timeout in milliseconds to wait for the receive.
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
/// otherwise the same buffer that was passed in to `recv`.
STATIC const mp_arg_t pyb_spi_recv_args[] = {
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
@ -363,6 +399,17 @@ STATIC mp_obj_t pyb_spi_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_recv_obj, 1, pyb_spi_recv);
/// \method send_recv(send, recv=None, *, timeout=5000)
///
/// Send and receive data on the bus at the same time:
///
/// - `send` is the data to send (an integer to send, or a buffer object).
/// - `recv` is a mutable buffer which will be filled with received bytes.
/// It can be the same as `send`, or omitted. If omitted, a new buffer will
/// be created.
/// - `timeout` is the timeout in milliseconds to wait for the receive.
///
/// Return value: the buffer with the received bytes.
STATIC const mp_arg_t pyb_spi_send_recv_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_recv, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
@ -436,6 +483,10 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj },
// class constants
/// \constant MASTER - for initialising the bus to master mode
/// \constant SLAVE - for initialising the bus to slave mode
/// \constant MSB - set the first bit to MSB
/// \constant LSB - set the first bit to LSB
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(SPI_MODE_SLAVE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(SPI_FIRSTBIT_MSB) },

Wyświetl plik

@ -12,20 +12,25 @@
#include "bufhelper.h"
#include "uart.h"
// Usage model:
//
// See usage model of I2C in i2c.c. UART is very similar. Main difference is
// parameters to init the UART bus:
//
// from pyb import UART
// uart = UART(1, 9600) # init with given baudrate
// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters
//
// Bits can be 8 or 9, stop can be 1 or 2, parity can be None, 0 (even), 1 (odd).
//
// Extra method:
//
// uart.any() # returns True if any characters waiting
/// \moduleref pyb
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol. At
/// the physical level it consists of 2 lines: RX and TX.
///
/// See usage model of I2C. UART is very similar. Main difference is
/// parameters to init the UART bus:
///
/// from pyb import UART
///
/// uart = UART(1, 9600) # init with given baudrate
/// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters
///
/// Bits can be 8 or 9, stop can be 1 or 2, parity can be None, 0 (even), 1 (odd).
///
/// Extra method:
///
/// uart.any() # returns True if any characters waiting
struct _pyb_uart_obj_t {
mp_obj_base_t base;
@ -225,6 +230,14 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void
}
}
/// \method init(baudrate, *, bits=8, stop=1, parity=None)
///
/// Initialise the SPI bus with the given parameters:
///
/// - `baudrate` is the clock rate.
/// - `bits` is the number of bits per byte, 8 or 9.
/// - `stop` is the number of stop bits, 1 or 2.
/// - `parity` is the parity, `None`, 0 (even) or 1 (odd).
STATIC const mp_arg_t pyb_uart_init_args[] = {
{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
@ -265,6 +278,13 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, uint n_args, const mp
return mp_const_none;
}
/// \classmethod \constructor(bus, ...)
///
/// Construct a UART object on the given bus. `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
/// With no additional parameters, the UART object is created but not
/// initialised (it has the settings from the last initialisation of
/// the bus, if any). If extra arguments are given, the bus is initialised.
/// See `init` for parameters of initialisation.
STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
@ -310,6 +330,8 @@ STATIC mp_obj_t pyb_uart_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
/// \method deinit()
/// Turn off the UART bus.
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
uart_deinit(self);
@ -317,6 +339,8 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
/// \method any()
/// Return `True` if any characters waiting, else `False`.
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
if (uart_rx_any(self)) {
@ -327,6 +351,13 @@ STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
/// \method send(send, *, timeout=5000)
/// Send data on the bus:
///
/// - `send` is the data to send (an integer to send, or a buffer object).
/// - `timeout` is the timeout in milliseconds to wait for the send.
///
/// Return value: `None`.
STATIC const mp_arg_t pyb_uart_send_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
@ -359,6 +390,16 @@ STATIC mp_obj_t pyb_uart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_send_obj, 1, pyb_uart_send);
/// \method recv(recv, *, timeout=5000)
///
/// Receive data on the bus:
///
/// - `recv` can be an integer, which is the number of bytes to receive,
/// or a mutable buffer, which will be filled with received bytes.
/// - `timeout` is the timeout in milliseconds to wait for the receive.
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
/// otherwise the same buffer that was passed in to `recv`.
STATIC const mp_arg_t pyb_uart_recv_args[] = {
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },

Wyświetl plik

@ -14,17 +14,22 @@
#if MICROPY_HW_HAS_SWITCH
// Usage Model:
//
// sw = pyb.Switch() # create a switch object
// sw() # get state (True if pressed, False otherwise)
// sw.callback(f) # register a callback to be called when the
// # switch is pressed down
// sw.callback(None) # remove the callback
//
// Example:
//
// pyb.Switch().callback(lambda: pyb.LED(1).toggle())
/// \moduleref pyb
/// \class Switch - switch object
///
/// A Switch object is used to control a push-button switch.
///
/// Usage:
///
/// sw = pyb.Switch() # create a switch object
/// sw() # get state (True if pressed, False otherwise)
/// sw.callback(f) # register a callback to be called when the
/// # switch is pressed down
/// sw.callback(None) # remove the callback
///
/// Example:
///
/// pyb.Switch().callback(lambda: pyb.LED(1).toggle())
// this function inits the switch GPIO so that it can be used
void switch_init0(void) {
@ -55,6 +60,8 @@ void pyb_switch_print(void (*print)(void *env, const char *fmt, ...), void *env,
print(env, "Switch()");
}
/// \classmethod \constructor()
/// Create and return a switch object.
STATIC mp_obj_t pyb_switch_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
@ -70,6 +77,8 @@ STATIC mp_obj_t pyb_switch_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
return (mp_obj_t)&pyb_switch_obj;
}
/// \method \call()
/// Return the switch state: `True` if pressed down, `False` otherwise.
mp_obj_t pyb_switch_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// get switch state
mp_arg_check_num(n_args, n_kw, 0, 0, false);
@ -84,6 +93,9 @@ STATIC mp_obj_t switch_callback(mp_obj_t line) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(switch_callback_obj, switch_callback);
/// \method callback(fun)
/// Register the given function to be called when the switch is pressed down.
/// If `fun` is `None`, then it disables the callback.
mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) {
pyb_switch_obj_t *self = self_in;
self->callback = callback;