diff --git a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp index affda7e2..d70c16d4 100644 --- a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp +++ b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.cpp @@ -1,5 +1,6 @@ #include "breakout_encoder_wheel.hpp" #include +#include namespace pimoroni { @@ -13,7 +14,21 @@ namespace pimoroni { ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B); - success = true; + if(led_ring.init()) { + led_ring.enable({ + 0b00000000, 0b10111111, + 0b00111110, 0b00111110, + 0b00111111, 0b10111110, + 0b00000111, 0b10000110, + 0b00110000, 0b00110000, + 0b00111111, 0b10111110, + 0b00111111, 0b10111110, + 0b01111111, 0b11111110, + 0b01111111, 0b00000000 + }, 0); + + success = true; + } } return success; @@ -55,22 +70,127 @@ namespace pimoroni { ioe.clear_interrupt_flag(); } - BreakoutEncoderWheel::Direction BreakoutEncoderWheel::get_encoder_direction() { - //return direction; - return DEFAULT_DIRECTION; + bool BreakoutEncoderWheel::pressed(uint button) { + return 0; // TODO } - void BreakoutEncoderWheel::set_encoder_direction(Direction direction) { - //this->direction = direction; + int BreakoutEncoderWheel::count() { + return 0; // TODO } - void BreakoutEncoderWheel::set_pixel(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { + int BreakoutEncoderWheel::delta() { + return 0; // TODO + } + + int BreakoutEncoderWheel::step() { + return 0; // TODO + } + + int BreakoutEncoderWheel::turn() { + return 0; // TODO + } + + void BreakoutEncoderWheel::zero() { + + } + + float BreakoutEncoderWheel::revolutions() { + return 0; // TODO + } + + float BreakoutEncoderWheel::degrees() { + return 0; // TODO + } + + float BreakoutEncoderWheel::radians() { + return 0; // TODO + } + + Direction BreakoutEncoderWheel::direction() { + return enc_direction; + } + + void BreakoutEncoderWheel::direction(Direction direction) { + enc_direction = direction; + } + + void BreakoutEncoderWheel::set_rgb(int index, int r, int g, int b) { RGBLookup rgb = lookup_table[index]; led_ring.set(rgb.r, r); led_ring.set(rgb.g, g); led_ring.set(rgb.b, b); } + void BreakoutEncoderWheel::set_hsv(int index, float h, float s, float v) { + int r, g, b; + if(h < 0.0f) { + h = 1.0f + fmod(h, 1.0f); + } + + int i = int(h * 6); + float f = h * 6 - i; + + v = v * 255.0f; + + float sv = s * v; + float fsv = f * sv; + + auto p = uint8_t(-sv + v); + auto q = uint8_t(-fsv + v); + auto t = uint8_t(fsv - sv + v); + + uint8_t bv = uint8_t(v); + + switch (i % 6) { + default: + case 0: r = bv; g = t; b = p; break; + case 1: r = q; g = bv; b = p; break; + case 2: r = p; g = bv; b = t; break; + case 3: r = p; g = q; b = bv; break; + case 4: r = t; g = p; b = bv; break; + case 5: r = bv; g = p; b = q; break; + } + + set_rgb(index, r, g, b); + } + + void BreakoutEncoderWheel::clear() { + led_ring.clear(); + } + + void BreakoutEncoderWheel::show() { + led_ring.update(); + } + + int BreakoutEncoderWheel::gpio_pin_mode(int gpio) { + return 0; // TODO + } + + void BreakoutEncoderWheel::gpio_pin_mode(int gpio, int mode) { + + } + + int BreakoutEncoderWheel::gpio_pin_value(int gpio) { + return 0; // TODO + } + + float BreakoutEncoderWheel::gpio_pin_value_as_voltage(int gpio) { + return 0; // TODO + } + + void BreakoutEncoderWheel::gpio_pin_value(int gpio, int value, bool load, bool wait_for_load) { + + } + + void BreakoutEncoderWheel::gpio_pwm_load(bool wait_for_load) { + + } + + int BreakoutEncoderWheel::gpio_pwm_frequency(float frequency, bool load, bool wait_for_load) { + return 0; // TODO + } + + /* bool BreakoutEncoderWheel::wheel_available() { return (ioe.get_interrupt_flag() > 0); } @@ -84,8 +204,5 @@ namespace pimoroni { //return count; return 0; } - - void BreakoutEncoderWheel::clear_wheel() { - ioe.clear_rotary_encoder(ENC_CHANNEL); - } + */ } \ No newline at end of file diff --git a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp index 26c82054..df8f95b9 100644 --- a/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp +++ b/libraries/breakout_encoder_wheel/breakout_encoder_wheel.hpp @@ -13,15 +13,6 @@ namespace pimoroni { uint8_t b; }; - //-------------------------------------------------- - // Enums - //-------------------------------------------------- - public: - enum Direction : bool { - DIRECTION_CW = true, - DIRECTION_CCW = false - }; - //-------------------------------------------------- // Constants @@ -29,22 +20,21 @@ namespace pimoroni { public: static const uint8_t DEFAULT_IOE_I2C_ADDRESS = 0x13; static const uint8_t DEFAULT_LED_I2C_ADDRESS = 0x77; - static const uint8_t LED_I2C_ADDRESS_ALTERNATE = 0x74; + static const uint8_t ALTERNATE_LED_I2C_ADDRESS = 0x74; - static const Direction DEFAULT_DIRECTION = DIRECTION_CW; + static const Direction DEFAULT_DIRECTION = NORMAL_DIR; static const uint32_t DEFAULT_TIMEOUT = 1; private: - static const uint8_t SWITCH_CENTRE = 1; - static const uint8_t SWITCH_UP = 13; - static const uint8_t SWITCH_LEFT = 11; - static const uint8_t SWITCH_DOWN = 4; - static const uint8_t SWITCH_RIGHT = 2; - + static const uint8_t ENC_CHANNEL = 1; static const uint8_t ENC_TERM_A = 12; static const uint8_t ENC_TERM_B = 3; - static const uint8_t ENC_CHANNEL = 1; + static const uint8_t SW_UP = 13; + static const uint8_t SW_DOWN = 4; + static const uint8_t SW_LEFT = 11; + static const uint8_t SW_RIGHT = 2; + static const uint8_t SW_CENTRE = 1; // This wonderful lookup table maps the LEDs on the encoder wheel // from their 3x24 (remember, they're RGB) configuration to @@ -85,7 +75,7 @@ namespace pimoroni { IS31FL3731 led_ring; //Direction direction = DEFAULT_DIRECTION; uint interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation - + Direction enc_direction = DEFAULT_DIRECTION; //-------------------------------------------------- // Constructors/Destructor @@ -118,17 +108,29 @@ namespace pimoroni { void clear_interrupt_flag(); // Encoder breakout specific - Direction get_encoder_direction(); - void set_encoder_direction(Direction direction); + bool pressed(uint button); + int count(); + int delta(); + int step(); + int turn(); + void zero(); + float revolutions(); + float degrees(); + float radians(); + Direction direction(); + void direction(Direction direction); + void set_rgb(int index, int r, int g, int b); + void set_hsv(int index, float h, float s = 1.0f, float v = 1.0f); + void clear(); + void show(); - void set_pixel(uint8_t index, uint8_t r, uint8_t g, uint8_t b); - //void update(uint8_t frame = 0); - //void clear(); - - bool wheel_available(); - int16_t read_wheel(); - void clear_wheel(); - bool read_switch(); + int gpio_pin_mode(int gpio); + void gpio_pin_mode(int gpio, int mode); + int gpio_pin_value(int gpio); + float gpio_pin_value_as_voltage(int gpio); + void gpio_pin_value(int gpio, int value, bool load = true, bool wait_for_load = false); + void gpio_pwm_load(bool wait_for_load = false); + int gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false); }; } \ No newline at end of file diff --git a/micropython/examples/breakout_encoder_wheel/clock.py b/micropython/examples/breakout_encoder_wheel/clock.py index fa67b5b0..a2fbdccb 100644 --- a/micropython/examples/breakout_encoder_wheel/clock.py +++ b/micropython/examples/breakout_encoder_wheel/clock.py @@ -1,5 +1,5 @@ import time -from datetime import datetime +from machine import RTC from pimoroni_i2c import PimoroniI2C from breakout_encoder_wheel import BreakoutEncoderWheel, NUM_LEDS @@ -13,6 +13,12 @@ Press Ctrl+C to stop the program. PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5} PINS_PICO_EXPLORER = {"sda": 20, "scl": 21} +# Datetime Indices +HOUR = 4 +MINUTE = 5 +SECOND = 6 +MICROSECOND = 7 + # Constants BRIGHTNESS = 1.0 # The brightness of the LEDs UPDATES = 50 # How many times the LEDs will be updated per second @@ -27,12 +33,13 @@ MILLIS_PER_HALF_DAY = MILLIS_PER_HOUR * 12 # Create a new BreakoutEncoderWheel i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN) wheel = BreakoutEncoderWheel(i2c) +rtc = machine.RTC() # Sleep until a specific time in the future. Use this instead of time.sleep() to correct for # inconsistent timings when dealing with complex operations or external communication def sleep_until(end_time): - time_to_sleep = end_time - time.monotonic() + time_to_sleep = end_time - (time.ticks_ms() / 1000) if time_to_sleep > 0.0: time.sleep(time_to_sleep) @@ -58,22 +65,22 @@ def led_brightness_at(led, position, half_width=1, span=1): elif lower < 0.0: brightness = clamp((led - (lower + NUM_LEDS)) / span, brightness, 1.0) - return brightness * BRIGHTNESS * 255 + return int(brightness * BRIGHTNESS * 255) # Make rainbows while True: # Record the start time of this loop - start_time = time.monotonic() + start_time = time.ticks_ms() / 1000 # Get the current system time - now = datetime.now() + now = rtc.datetime() # Convert the seconds, minutes, and hours into milliseconds (this is done to give a smoother animation, particularly for the seconds hand) - sec_as_millis = (now.second * MILLIS_PER_SECOND) + (now.microsecond // MILLIS_PER_SECOND) - min_as_millis = (now.minute * MILLIS_PER_MINUTE) + sec_as_millis - hour_as_millis = ((now.hour % 12) * MILLIS_PER_HOUR) + min_as_millis + sec_as_millis = (now[SECOND] * MILLIS_PER_SECOND) + (now[MICROSECOND] // MILLIS_PER_SECOND) + min_as_millis = (now[MINUTE] * MILLIS_PER_MINUTE) + sec_as_millis + hour_as_millis = ((now[HOUR] % 12) * MILLIS_PER_HOUR) + min_as_millis # Calculate the position on the LED ring that the, second, minute, and hour hands should be sec_pos = min(sec_as_millis / MILLIS_PER_MINUTE, 1.0) * NUM_LEDS diff --git a/micropython/examples/breakout_encoder_wheel/colour_picker.py b/micropython/examples/breakout_encoder_wheel/colour_picker.py index 24c1836a..583e6668 100644 --- a/micropython/examples/breakout_encoder_wheel/colour_picker.py +++ b/micropython/examples/breakout_encoder_wheel/colour_picker.py @@ -1,5 +1,4 @@ import time -from colorsys import hsv_to_rgb from pimoroni_i2c import PimoroniI2C from breakout_encoder_wheel import BreakoutEncoderWheel, UP, DOWN, LEFT, RIGHT, CENTRE, NUM_LEDS @@ -38,6 +37,30 @@ changed = True last_centre_pressed = False +# From CPython Lib/colorsys.py +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + # Simple function to clamp a value between 0.0 and 1.0 def clamp01(value): return max(min(value, 1.0), 0.0) @@ -46,14 +69,14 @@ def clamp01(value): # Sleep until a specific time in the future. Use this instead of time.sleep() to correct for # inconsistent timings when dealing with complex operations or external communication def sleep_until(end_time): - time_to_sleep = end_time - time.monotonic() + time_to_sleep = end_time - (time.ticks_ms() / 1000) if time_to_sleep > 0.0: time.sleep(time_to_sleep) while True: # Record the start time of this loop - start_time = time.monotonic() + start_time = time.ticks_ms() / 1000 # If up is pressed, increase the brightness if wheel.pressed(UP): @@ -95,7 +118,7 @@ while True: if changed: # Print the colour at the current hue, saturation, and brightness r, g, b = [int(c * 255) for c in hsv_to_rgb(position / NUM_LEDS, saturation, brightness)] - print("Colour Code = #", hex(r)[2:].zfill(2), hex(g)[2:].zfill(2), hex(b)[2:].zfill(2), sep="") + print("Colour Code = #", '{:02x}'.format(r), '{:02x}'.format(g), '{:02x}'.format(b), sep="") # Set the LED at the current position to either the actual colour, # or an inverted version to show a "selection marker" diff --git a/micropython/examples/breakout_encoder_wheel/gpio_pwm.py b/micropython/examples/breakout_encoder_wheel/gpio_pwm.py index e877a9b5..b8bb0d46 100644 --- a/micropython/examples/breakout_encoder_wheel/gpio_pwm.py +++ b/micropython/examples/breakout_encoder_wheel/gpio_pwm.py @@ -1,7 +1,7 @@ import math import time -from ioexpander import PWM +from breakout_ioexpander import BreakoutIOExpander from pimoroni_i2c import PimoroniI2C from breakout_encoder_wheel import BreakoutEncoderWheel, CENTRE, GPIOS, NUM_GPIOS @@ -28,7 +28,7 @@ period = wheel.gpio_pwm_frequency(FREQUENCY) # Set the GPIO pins to PWM outputs for g in GPIOS: - wheel.gpio_pin_mode(g, PWM) + wheel.gpio_pin_mode(g, BreakoutIOExpander.PIN_PWM) offset = 0.0 @@ -36,7 +36,7 @@ offset = 0.0 # Sleep until a specific time in the future. Use this instead of time.sleep() to correct for # inconsistent timings when dealing with complex operations or external communication def sleep_until(end_time): - time_to_sleep = end_time - time.monotonic() + time_to_sleep = end_time - (time.ticks_ms() / 1000) if time_to_sleep > 0.0: time.sleep(time_to_sleep) @@ -45,7 +45,7 @@ def sleep_until(end_time): while not wheel.pressed(CENTRE): # Record the start time of this loop - start_time = time.monotonic() + start_time = time.ticks_ms() / 1000 offset += SPEED / 1000.0 diff --git a/micropython/examples/breakout_encoder_wheel/led_rainbow.py b/micropython/examples/breakout_encoder_wheel/led_rainbow.py index 76f780ba..eef15328 100644 --- a/micropython/examples/breakout_encoder_wheel/led_rainbow.py +++ b/micropython/examples/breakout_encoder_wheel/led_rainbow.py @@ -29,7 +29,7 @@ offset = 0.0 # Sleep until a specific time in the future. Use this instead of time.sleep() to correct for # inconsistent timings when dealing with complex operations or external communication def sleep_until(end_time): - time_to_sleep = end_time - time.monotonic() + time_to_sleep = end_time - (time.ticks_ms() / 1000) if time_to_sleep > 0.0: time.sleep(time_to_sleep) @@ -38,7 +38,7 @@ def sleep_until(end_time): while True: # Record the start time of this loop - start_time = time.monotonic() + start_time = time.ticks_ms() / 1000 offset += SPEED / 1000.0 diff --git a/micropython/examples/breakout_encoder_wheel/stop_watch.py b/micropython/examples/breakout_encoder_wheel/stop_watch.py index 240def09..e7fac17b 100644 --- a/micropython/examples/breakout_encoder_wheel/stop_watch.py +++ b/micropython/examples/breakout_encoder_wheel/stop_watch.py @@ -49,13 +49,13 @@ def clamp(n, smallest, largest): # Sleep until a specific time in the future. Use this instead of time.sleep() to correct for # inconsistent timings when dealing with complex operations or external communication def sleep_until(end_time): - time_to_sleep = end_time - time.monotonic() + time_to_sleep = end_time - (time.ticks_ms() / 1000) if time_to_sleep > 0.0: time.sleep(time_to_sleep) # Record the current time -current_time = time.monotonic() +current_time = (time.ticks_ms() / 1000) # Run the update loop forever while True: diff --git a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c index ee813643..dabb5301 100644 --- a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c +++ b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.c @@ -104,7 +104,7 @@ STATIC const mp_rom_map_elem_t breakout_encoder_wheel_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_LEFT), MP_ROM_INT(2) }, { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_INT(3) }, - { MP_ROM_QSTR(MP_QSTR_CENTRE), MP_ROM_INT(5) }, + { MP_ROM_QSTR(MP_QSTR_CENTRE), MP_ROM_INT(4) }, { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_INT(7) }, { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_INT(8) }, diff --git a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp index 4d6c78f6..41361e03 100644 --- a/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp +++ b/micropython/modules/breakout_encoder_wheel/breakout_encoder_wheel.cpp @@ -81,7 +81,7 @@ extern mp_obj_t BreakoutEncoderWheel_pressed(mp_obj_t self_in, mp_obj_t button_i int button = mp_obj_get_int(button_in); if(button < 0 || button >= 5) { - mp_raise_ValueError("button out of range. Expected 0 to 4") + mp_raise_ValueError("button out of range. Expected 0 to 4"); } return mp_obj_new_bool(self->breakout->pressed(button)); @@ -195,9 +195,9 @@ extern mp_obj_t BreakoutEncoderWheel_set_hsv(size_t n_args, const mp_obj_t *pos_ static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_s, MP_ARG_INT, { .u_obj = mp_const_none }}, - { MP_QSTR_v, MP_ARG_INT, { .u_obj = mp_const_none }}, + { MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_s, MP_ARG_OBJ, { .u_obj = mp_const_none }}, + { MP_QSTR_v, MP_ARG_OBJ, { .u_obj = mp_const_none }}, }; // Parse args.