pimoroni-pico/micropython/modules/motor/motor.cpp

2209 lines
88 KiB
C++

#include "drivers/motor/motor.hpp"
#include "drivers/motor/motor_cluster.hpp"
#include "common/pimoroni_common.hpp"
#include "micropython/modules/util.hpp"
#include <cstdio>
using namespace pimoroni;
using namespace motor;
extern "C" {
#include "motor.h"
#include "py/builtin.h"
#include "float.h"
void pimoroni_tuple_or_list(const mp_obj_t &object, mp_obj_t **items, size_t *length) {
if(mp_obj_is_type(object, &mp_type_list)) {
mp_obj_list_t *list = MP_OBJ_TO_PTR2(object, mp_obj_list_t);
*length = list->len;
*items = list->items;
}
else if(mp_obj_is_type(object, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(object, mp_obj_tuple_t);
*length = tuple->len;
*items = tuple->items;
}
if(*items == nullptr) {
mp_raise_TypeError("cannot convert object to a list or tuple of integers, or a single integer");
} else if(*length == 0) {
mp_raise_TypeError("list or tuple must contain at least one integer");
}
}
uint8_t* pimoroni_motors_from_items(mp_obj_t *items, size_t length, int motor_count) {
uint8_t *motors = new uint8_t[length];
for(size_t i = 0; i < length; i++) {
int motor = mp_obj_get_int(items[i]);
if(motor < 0 || motor >= motor_count) {
delete[] motors;
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a motor in the list or tuple is out of range. Expected 0 to %d"), motor_count - 1);
}
else {
motors[i] = (uint8_t)motor;
}
}
return motors;
}
/********** Motor **********/
/***** Variables Struct *****/
typedef struct _Motor_obj_t {
mp_obj_base_t base;
Motor* motor;
} _Motor_obj_t;
/***** Print *****/
void Motor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; //Unused input parameter
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
mp_print_str(print, "Motor(");
mp_print_str(print, "pins = (");
pin_pair pins = self->motor->pins();
mp_obj_print_helper(print, mp_obj_new_int(pins.positive), PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_obj_new_int(pins.negative), PRINT_REPR);
mp_print_str(print, "), enabled = ");
mp_obj_print_helper(print, self->motor->is_enabled() ? mp_const_true : mp_const_false, PRINT_REPR);
mp_print_str(print, ", duty = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->duty()), PRINT_REPR);
mp_print_str(print, ", speed = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->speed()), PRINT_REPR);
mp_print_str(print, ", freq = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->frequency()), PRINT_REPR);
if(self->motor->direction() == NORMAL_DIR)
mp_print_str(print, ", direction = NORMAL_DIR");
else
mp_print_str(print, ", direction = REVERSED_DIR");
mp_print_str(print, ", speed_scale = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->speed_scale()), PRINT_REPR);
mp_print_str(print, ", zeropoint = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->zeropoint()), PRINT_REPR);
mp_print_str(print, ", deadzone = ");
mp_obj_print_helper(print, mp_obj_new_float(self->motor->deadzone()), PRINT_REPR);
if(self->motor->decay_mode() == SLOW_DECAY)
mp_print_str(print, ", decay_mode = SLOW_DECAY");
else
mp_print_str(print, ", decay_mode = FAST_DECAY");
mp_print_str(print, ")");
}
/***** Constructor *****/
mp_obj_t Motor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_Motor_obj_t *self = nullptr;
enum { ARG_pins, ARG_direction, ARG_speed_scale, ARG_zeropoint, ARG_deadzone, ARG_freq, ARG_mode, ARG_ph_en_driver };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_direction, MP_ARG_INT, {.u_int = NORMAL_DIR} },
{ MP_QSTR_speed_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_zeropoint, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_deadzone, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_freq, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = MotorState::DEFAULT_DECAY_MODE} },
{ MP_QSTR_ph_en_driver, MP_ARG_BOOL, {.u_bool = false} }
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
size_t pin_count = 0;
pin_pair pins;
// Determine what pair of pins this motor will use
const mp_obj_t object = args[ARG_pins].u_obj;
mp_obj_t *items = nullptr;
if(mp_obj_is_type(object, &mp_type_list)) {
mp_obj_list_t *list = MP_OBJ_TO_PTR2(object, mp_obj_list_t);
pin_count = list->len;
items = list->items;
}
else if(mp_obj_is_type(object, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(object, mp_obj_tuple_t);
pin_count = tuple->len;
items = tuple->items;
}
if(items == nullptr)
mp_raise_TypeError("cannot convert object to a list or tuple of pins");
else if(pin_count != 2)
mp_raise_TypeError("list or tuple must only contain two integers");
else {
int pos = mp_obj_get_int(items[0]);
int neg = mp_obj_get_int(items[1]);
if((pos < 0 || pos >= (int)NUM_BANK0_GPIOS) ||
(neg < 0 || neg >= (int)NUM_BANK0_GPIOS)) {
mp_raise_ValueError("a pin in the list or tuple is out of range. Expected 0 to 29");
}
else if(pos == neg) {
mp_raise_ValueError("cannot use the same pin for motor positive and negative");
}
pins.positive = (uint8_t)pos;
pins.negative = (uint8_t)neg;
}
int direction = args[ARG_direction].u_int;
if(direction < 0 || direction > 1) {
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
float speed_scale = MotorState::DEFAULT_SPEED_SCALE;
if(args[ARG_speed_scale].u_obj != mp_const_none) {
speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
}
float zeropoint = MotorState::DEFAULT_ZEROPOINT;
if(args[ARG_zeropoint].u_obj != mp_const_none) {
zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
}
float deadzone = MotorState::DEFAULT_DEADZONE;
if(args[ARG_deadzone].u_obj != mp_const_none) {
deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
}
float freq = MotorState::DEFAULT_FREQUENCY;
if(args[ARG_freq].u_obj != mp_const_none) {
freq = mp_obj_get_float(args[ARG_freq].u_obj);
}
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 1) {
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
self = m_new_obj_with_finaliser(_Motor_obj_t);
self->base.type = &Motor_type;
self->motor = m_new_class(Motor, pins, (Direction)direction, speed_scale, zeropoint, deadzone, freq, (DecayMode)mode, args[ARG_ph_en_driver].u_bool);
self->motor->init();
return MP_OBJ_FROM_PTR(self);
}
/***** Destructor ******/
mp_obj_t Motor___del__(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
m_del_class(Motor, self->motor);
return mp_const_none;
}
/***** Methods *****/
extern mp_obj_t Motor_pins(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
pin_pair pins = self->motor->pins();
mp_obj_t tuple[2];
tuple[0] = mp_obj_new_int(pins.positive);
tuple[1] = mp_obj_new_int(pins.negative);
return mp_obj_new_tuple(2, tuple);
}
extern mp_obj_t Motor_enable(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->enable();
return mp_const_none;
}
extern mp_obj_t Motor_disable(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->disable();
return mp_const_none;
}
extern mp_obj_t Motor_is_enabled(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
return self->motor->is_enabled() ? mp_const_true : mp_const_false;
}
extern mp_obj_t Motor_duty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_duty };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_duty, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->duty());
}
else {
self->motor->duty(mp_obj_get_float(args[ARG_duty].u_obj));
return mp_const_none;
}
}
extern mp_obj_t Motor_speed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_speed };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->speed());
}
else {
self->motor->speed(mp_obj_get_float(args[ARG_speed].u_obj));
return mp_const_none;
}
}
extern mp_obj_t Motor_frequency(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_freq };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_freq, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->frequency());
}
else {
if(!self->motor->frequency(mp_obj_get_float(args[ARG_freq].u_obj))) {
mp_raise_ValueError("freq out of range. Expected 10Hz to 400KHz");
}
return mp_const_none;
}
}
extern mp_obj_t Motor_stop(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->stop();
return mp_const_none;
}
extern mp_obj_t Motor_coast(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->coast();
return mp_const_none;
}
extern mp_obj_t Motor_brake(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->brake();
return mp_const_none;
}
extern mp_obj_t Motor_full_negative(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->full_negative();
return mp_const_none;
}
extern mp_obj_t Motor_full_positive(mp_obj_t self_in) {
_Motor_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Motor_obj_t);
self->motor->full_positive();
return mp_const_none;
}
extern mp_obj_t Motor_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
if(n_args <= 2) {
enum { ARG_self, ARG_in };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
float in = mp_obj_get_float(args[ARG_in].u_obj);
self->motor->to_percent(in);
}
else if(n_args <= 4) {
enum { ARG_self, ARG_in, ARG_in_min, ARG_in_max };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
self->motor->to_percent(in, in_min, in_max);
}
else {
enum { ARG_self, ARG_in, ARG_in_min, ARG_in_max, ARG_speed_min, ARG_speed_max };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_max, MP_ARG_REQUIRED | MP_ARG_OBJ }
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
float speed_min = mp_obj_get_float(args[ARG_speed_min].u_obj);
float speed_max = mp_obj_get_float(args[ARG_speed_max].u_obj);
self->motor->to_percent(in, in_min, in_max, speed_min, speed_max);
}
return mp_const_none;
}
extern mp_obj_t Motor_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_direction };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_direction, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_int(self->motor->direction());
}
else {
int direction = mp_obj_get_int(args[ARG_direction].u_obj);
if(direction < 0 || direction > 1) {
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
self->motor->direction((Direction)direction);
return mp_const_none;
}
}
extern mp_obj_t Motor_speed_scale(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_speed_scale };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_scale, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->speed_scale());
}
else {
float speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
self->motor->speed_scale(speed_scale);
return mp_const_none;
}
}
extern mp_obj_t Motor_zeropoint(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_zeropoint };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_zeropoint, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->zeropoint());
}
else {
float zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
self->motor->zeropoint(zeropoint);
return mp_const_none;
}
}
extern mp_obj_t Motor_deadzone(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_deadzone };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_deadzone, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->motor->deadzone());
}
else {
float deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
self->motor->deadzone(deadzone);
return mp_const_none;
}
}
extern mp_obj_t Motor_decay_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_mode };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mode, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_Motor_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _Motor_obj_t);
if(n_args <= 1) {
return mp_obj_new_int(self->motor->decay_mode());
}
else {
int mode = mp_obj_get_int(args[ARG_mode].u_obj);
if(mode < 0 || mode > 1) {
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
self->motor->decay_mode((DecayMode)mode);
return mp_const_none;
}
}
/********** MotorCluster **********/
/***** Variables Struct *****/
typedef struct _MotorCluster_obj_t {
mp_obj_base_t base;
MotorCluster* cluster;
} _MotorCluster_obj_t;
/***** Print *****/
void MotorCluster_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; //Unused input parameter
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(self_in, _MotorCluster_obj_t);
mp_print_str(print, "MotorCluster(");
mp_print_str(print, "motors = {");
uint8_t motor_count = self->cluster->count();
for(uint8_t motor = 0; motor < motor_count; motor++) {
mp_print_str(print, "\n\t{pins = (");
pin_pair pins = self->cluster->pins(motor);
mp_obj_print_helper(print, mp_obj_new_int(pins.positive), PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_obj_new_int(pins.negative), PRINT_REPR);
mp_print_str(print, "), enabled = ");
mp_obj_print_helper(print, self->cluster->is_enabled(motor) ? mp_const_true : mp_const_false, PRINT_REPR);
mp_print_str(print, ", duty = ");
mp_obj_print_helper(print, mp_obj_new_float(self->cluster->duty(motor)), PRINT_REPR);
mp_print_str(print, ", speed = ");
mp_obj_print_helper(print, mp_obj_new_float(self->cluster->speed(motor)), PRINT_REPR);
mp_print_str(print, ", phase = ");
mp_obj_print_helper(print, mp_obj_new_float(self->cluster->phase(motor)), PRINT_REPR);
mp_print_str(print, "}");
if(motor < motor_count - 1)
mp_print_str(print, ", ");
}
if(motor_count > 0) {
mp_print_str(print, "\n");
}
mp_print_str(print, "}, freq = ");
mp_obj_print_helper(print, mp_obj_new_float(self->cluster->frequency()), PRINT_REPR);
mp_print_str(print, ")");
}
/***** Constructor *****/
mp_obj_t MotorCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_MotorCluster_obj_t *self = nullptr;
enum { ARG_pio, ARG_sm, ARG_pins, ARG_direction, ARG_speed_scale, ARG_zeropoint, ARG_deadzone, ARG_freq, ARG_mode, ARG_auto_phase };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_direction, MP_ARG_INT, {.u_int = NORMAL_DIR} },
{ MP_QSTR_speed_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_zeropoint, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_deadzone, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_freq, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = MotorState::DEFAULT_DECAY_MODE} },
{ MP_QSTR_auto_phase, MP_ARG_BOOL, {.u_bool = true} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int pio_int = args[ARG_pio].u_int;
if(pio_int < 0 || pio_int > (int)NUM_PIOS) {
mp_raise_ValueError("pio out of range. Expected 0 to 1");
}
PIO pio = pio_int == 0 ? pio0 : pio1;
int sm = args[ARG_sm].u_int;
if(sm < 0 || sm > (int)NUM_PIO_STATE_MACHINES) {
mp_raise_ValueError("sm out of range. Expected 0 to 3");
}
size_t pair_count = 0;
pin_pair *pins = nullptr;
// Determine what pair of pins this motor will use
const mp_obj_t object = args[ARG_pins].u_obj;
mp_obj_t *items = nullptr;
if(mp_obj_is_type(object, &mp_type_list)) {
mp_obj_list_t *list = MP_OBJ_TO_PTR2(object, mp_obj_list_t);
pair_count = list->len;
items = list->items;
}
else if(mp_obj_is_type(object, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(object, mp_obj_tuple_t);
pair_count = tuple->len;
items = tuple->items;
}
if(items == nullptr)
mp_raise_TypeError("cannot convert object to a list or tuple of pins");
else if(pair_count == 0)
mp_raise_TypeError("list or tuple must contain at least one pair tuple");
else {
// Specific check for is a single 2 pin list/tuple was provided
if(pair_count == 2 && mp_obj_is_int(items[0]) && mp_obj_is_int(items[1])) {
pins = new pin_pair[1];
pair_count = 1;
int pos = mp_obj_get_int(items[0]);
int neg = mp_obj_get_int(items[1]);
if((pos < 0 || pos >= (int)NUM_BANK0_GPIOS) ||
(neg < 0 || neg >= (int)NUM_BANK0_GPIOS)) {
delete[] pins;
mp_raise_ValueError("a pin in the list or tuple is out of range. Expected 0 to 29");
}
else if(pos == neg) {
delete[] pins;
mp_raise_ValueError("cannot use the same pin for motor positive and negative");
}
pins[0].positive = (uint8_t)pos;
pins[0].negative = (uint8_t)neg;
}
else {
// Create and populate a local array of pins
pins = new pin_pair[pair_count];
for(size_t i = 0; i < pair_count; i++) {
mp_obj_t obj = items[i];
if(!mp_obj_is_type(obj, &mp_type_tuple)) {
delete[] pins;
mp_raise_ValueError("cannot convert item to a pair tuple");
}
else {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t);
if(tuple->len != 2) {
delete[] pins;
mp_raise_ValueError("pair tuple must only contain two integers");
}
int pos = mp_obj_get_int(tuple->items[0]);
int neg = mp_obj_get_int(tuple->items[1]);
if((pos < 0 || pos >= (int)NUM_BANK0_GPIOS) ||
(neg < 0 || neg >= (int)NUM_BANK0_GPIOS)) {
delete[] pins;
mp_raise_ValueError("a pin in the pair tuple is out of range. Expected 0 to 29");
}
else if(pos == neg) {
delete[] pins;
mp_raise_ValueError("cannot use the same pin for motor positive and negative");
}
pins[i].positive = (uint8_t)pos;
pins[i].negative = (uint8_t)neg;
}
}
}
}
int direction = args[ARG_direction].u_int;
if(direction < 0 || direction > 1) {
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
float speed_scale = MotorState::DEFAULT_SPEED_SCALE;
if(args[ARG_speed_scale].u_obj != mp_const_none) {
speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
}
float zeropoint = MotorState::DEFAULT_ZEROPOINT;
if(args[ARG_zeropoint].u_obj != mp_const_none) {
zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
}
float deadzone = MotorState::DEFAULT_DEADZONE;
if(args[ARG_deadzone].u_obj != mp_const_none) {
deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
}
float freq = MotorState::DEFAULT_FREQUENCY;
if(args[ARG_freq].u_obj != mp_const_none) {
freq = mp_obj_get_float(args[ARG_freq].u_obj);
}
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 1) {
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
bool auto_phase = args[ARG_auto_phase].u_bool;
MotorCluster *cluster = m_new_class(MotorCluster, pio, sm, pins, pair_count, (Direction)direction, speed_scale, zeropoint, deadzone,
freq, (DecayMode)mode, auto_phase);
// Cleanup the pins array
if(pins != nullptr)
delete[] pins;
if(!cluster->init()) {
m_del_class(MotorCluster, cluster);
mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this MotorCluster. Try running `import gc` followed by `gc.collect()` before creating it");
}
self = m_new_obj_with_finaliser(_MotorCluster_obj_t);
self->base.type = &MotorCluster_type;
self->cluster = cluster;
return MP_OBJ_FROM_PTR(self);
}
/***** Destructor ******/
mp_obj_t MotorCluster___del__(mp_obj_t self_in) {
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(self_in, _MotorCluster_obj_t);
m_del_class(MotorCluster, self->cluster);
return mp_const_none;
}
/***** Methods *****/
extern mp_obj_t MotorCluster_count(mp_obj_t self_in) {
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(self_in, _MotorCluster_obj_t);
return mp_obj_new_int(self->cluster->count());
}
extern mp_obj_t MotorCluster_pins(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_INT },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor = args[ARG_motor].u_int;
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
pin_pair pins = self->cluster->pins((uint)motor);
mp_obj_t tuple[2];
tuple[0] = mp_obj_new_int(pins.positive);
tuple[1] = mp_obj_new_int(pins.negative);
return mp_obj_new_tuple(2, tuple);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to enable
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->enable((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->enable(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_enable_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
self->cluster->enable_all(args[ARG_load].u_bool);
return mp_const_none;
}
extern mp_obj_t MotorCluster_disable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to disable
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->disable((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->disable(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_disable_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
self->cluster->disable_all(args[ARG_load].u_bool);
return mp_const_none;
}
extern mp_obj_t MotorCluster_is_enabled(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_INT },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor = args[ARG_motor].u_int;
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return self->cluster->is_enabled((uint)motor) ? mp_const_true : mp_const_false;
return mp_const_none;
}
extern mp_obj_t MotorCluster_duty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_duty, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_duty, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->duty((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float duty = mp_obj_get_float(args[ARG_duty].u_obj);
self->cluster->duty((uint)motor, duty, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float duty = mp_obj_get_float(args[ARG_duty].u_obj);
self->cluster->duty(motors, length, duty, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_to_duty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_duty, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_duty, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float duty = mp_obj_get_float(args[ARG_duty].u_obj);
self->cluster->all_to_duty(duty, args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_speed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_speed, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->speed((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float speed = mp_obj_get_float(args[ARG_speed].u_obj);
self->cluster->speed((uint)motor, speed, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float speed = mp_obj_get_float(args[ARG_speed].u_obj);
self->cluster->speed(motors, length, speed, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_to_speed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_speed, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float speed = mp_obj_get_float(args[ARG_speed].u_obj);
self->cluster->all_to_speed(speed, args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_phase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_phase, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_phase, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->phase((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float phase = mp_obj_get_float(args[ARG_phase].u_obj);
self->cluster->phase((uint)motor, phase, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float phase = mp_obj_get_float(args[ARG_phase].u_obj);
self->cluster->phase(motors, length, phase, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_to_phase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_phase, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_phase, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float phase = mp_obj_get_float(args[ARG_phase].u_obj);
self->cluster->all_to_phase(phase, args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_frequency(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_freq };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_freq, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
if(n_args <= 1) {
return mp_obj_new_float(self->cluster->frequency());
}
else {
float freq = mp_obj_get_float(args[ARG_freq].u_obj);
if(!self->cluster->frequency(freq))
mp_raise_ValueError("freq out of range. Expected 10Hz to 400KHz");
else
return mp_const_none;
}
}
extern mp_obj_t MotorCluster_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to stop
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->stop((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->stop(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_stop_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
self->cluster->stop_all(args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_coast(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to coast
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->coast((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->coast(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_coast_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
self->cluster->coast_all(args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_brake(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to brake
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->brake((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->brake(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_brake_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
self->cluster->brake_all(args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_full_negative(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to set to full negative
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->full_negative((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->full_negative(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_full_negative(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
self->cluster->all_full_negative(args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_full_positive(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motors, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to set to full positive
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
self->cluster->full_positive((uint)motor, args[ARG_load].u_bool);
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
self->cluster->full_positive(motors, length, args[ARG_load].u_bool);
delete[] motors;
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_full_positive(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
self->cluster->all_full_positive(args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
if(n_args <= 4) {
enum { ARG_self, ARG_motors, ARG_in, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
self->cluster->to_percent((uint)motor, in, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float in = mp_obj_get_float(args[ARG_in].u_obj);
self->cluster->to_percent(motors, length, in, args[ARG_load].u_bool);
delete[] motors;
}
}
}
else if(n_args <= 6) {
enum { ARG_self, ARG_motors, ARG_in, ARG_in_min, ARG_in_max, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
self->cluster->to_percent((uint)motor, in, in_min, in_max, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
self->cluster->to_percent(motors, length, in, in_min, in_max, args[ARG_load].u_bool);
delete[] motors;
}
}
}
else {
enum { ARG_self, ARG_motors, ARG_in, ARG_in_min, ARG_in_max, ARG_speed_min, ARG_speed_max, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motors, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motors].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
float speed_min = mp_obj_get_float(args[ARG_speed_min].u_obj);
float speed_max = mp_obj_get_float(args[ARG_speed_max].u_obj);
self->cluster->to_percent((uint)motor, in, in_min, in_max, speed_min, speed_max, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
float speed_min = mp_obj_get_float(args[ARG_speed_min].u_obj);
float speed_max = mp_obj_get_float(args[ARG_speed_max].u_obj);
self->cluster->to_percent(motors, length, in, in_min, in_max, speed_min, speed_max, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_to_percent(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
if(n_args <= 3) {
enum { ARG_self, ARG_in, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
self->cluster->all_to_percent(in, args[ARG_load].u_bool);
}
}
else if(n_args <= 5) {
enum { ARG_self, ARG_in, ARG_in_min, ARG_in_max, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
self->cluster->all_to_percent(in, in_min, in_max, args[ARG_load].u_bool);
}
}
else {
enum { ARG_self, ARG_in, ARG_in_min, ARG_in_max, ARG_speed_min, ARG_speed_max, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_in_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_min, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_max, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float in = mp_obj_get_float(args[ARG_in].u_obj);
float in_min = mp_obj_get_float(args[ARG_in_min].u_obj);
float in_max = mp_obj_get_float(args[ARG_in_max].u_obj);
float speed_min = mp_obj_get_float(args[ARG_speed_min].u_obj);
float speed_max = mp_obj_get_float(args[ARG_speed_max].u_obj);
self->cluster->all_to_percent(in, in_min, in_max, speed_min, speed_max, args[ARG_load].u_bool);
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_load(mp_obj_t self_in) {
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(self_in, _MotorCluster_obj_t);
self->cluster->load();
return mp_const_none;
}
extern mp_obj_t MotorCluster_direction(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_direction };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_direction, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_int((int)self->cluster->direction((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
int direction = mp_obj_get_int(args[ARG_direction].u_obj);
if(direction < 0 || direction > 1) {
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
self->cluster->direction((uint)motor, (Direction)direction);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
int direction = mp_obj_get_int(args[ARG_direction].u_obj);
if(direction < 0 || direction > 1) {
delete[] motors;
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
self->cluster->direction(motors, length, (Direction)direction);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_directions(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_direction };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_direction, MP_ARG_REQUIRED | MP_ARG_INT },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
int direction = args[ARG_direction].u_int;
if(direction < 0 || direction > 1) {
mp_raise_ValueError("direction out of range. Expected NORMAL_DIR (0) or REVERSED_DIR (1)");
}
self->cluster->all_directions((Direction)direction);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_speed_scale(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_speed_scale };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_scale, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->speed_scale((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
self->cluster->speed_scale((uint)motor, speed_scale);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
delete[] motors;
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
self->cluster->speed_scale(motors, length, speed_scale);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_speed_scales(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_speed_scale };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_speed_scale, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float speed_scale = mp_obj_get_float(args[ARG_speed_scale].u_obj);
if(speed_scale < FLT_EPSILON) {
mp_raise_ValueError("speed_scale out of range. Expected greater than 0.0");
}
self->cluster->all_speed_scales(speed_scale);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_zeropoint(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_zeropoint };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_zeropoint, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->zeropoint((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
self->cluster->zeropoint((uint)motor, zeropoint);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
delete[] motors;
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
self->cluster->zeropoint(motors, length, zeropoint);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_zeropoints(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_zeropoint };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_zeropoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float zeropoint = mp_obj_get_float(args[ARG_zeropoint].u_obj);
if(zeropoint < 0.0f || zeropoint > 1.0f - FLT_EPSILON) {
mp_raise_ValueError("zeropoint out of range. Expected 0.0 to less than 1.0");
}
self->cluster->all_zeropoints(zeropoint);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_deadzone(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_deadzone, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_deadzone, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_float(self->cluster->deadzone((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
float deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
self->cluster->deadzone((uint)motor, deadzone, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
float deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
delete[] motors;
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
self->cluster->deadzone(motors, length, deadzone, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_deadzones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_deadzone, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_deadzone, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
float deadzone = mp_obj_get_float(args[ARG_deadzone].u_obj);
if(deadzone < 0.0f || deadzone > 1.0f) {
mp_raise_ValueError("deadzone out of range. Expected 0.0 to 1.0");
}
self->cluster->all_deadzones(deadzone, args[ARG_load].u_bool);
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_decay_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_motor, ARG_mode, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_motor, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mode, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
if(n_args <= 2) {
int motor = mp_obj_get_int(args[ARG_motor].u_obj);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else
return mp_obj_new_int((int)self->cluster->decay_mode((uint)motor));
}
else {
// Determine what motor(s) to modify
const mp_obj_t object = args[ARG_motor].u_obj;
if(mp_obj_is_int(object)) {
int motor = mp_obj_get_int(object);
if(motor < 0 || motor >= motor_count)
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("motor out of range. Expected 0 to %d"), motor_count - 1);
else {
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 1) {
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
self->cluster->decay_mode((uint)motor, (DecayMode)mode, args[ARG_load].u_bool);
}
}
else {
size_t length = 0;
mp_obj_t *items = nullptr;
pimoroni_tuple_or_list(object, &items, &length);
// Create and populate a local array of motor indices
uint8_t *motors = pimoroni_motors_from_items(items, length, motor_count);
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 1) {
delete[] motors;
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
self->cluster->decay_mode(motors, length, (DecayMode)mode, args[ARG_load].u_bool);
delete[] motors;
}
}
}
return mp_const_none;
}
extern mp_obj_t MotorCluster_all_decay_modes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_mode, ARG_load };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_load, MP_ARG_BOOL, { .u_bool = true }},
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_MotorCluster_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _MotorCluster_obj_t);
int motor_count = (int)self->cluster->count();
if(motor_count == 0)
mp_raise_ValueError("this cluster does not have any motors");
else {
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 1) {
mp_raise_ValueError("mode out of range. Expected FAST_DECAY (0) or SLOW_DECAY (1)");
}
self->cluster->all_decay_modes((DecayMode)mode, args[ARG_load].u_bool);
}
return mp_const_none;
}
}