Merge pull request #711 from pimoroni/patch-jpegdec-filename

MicroPython: Avoid heap allocations in all C++ modules.
pull/723/head v1.19.17
Philip Howard 2023-03-17 14:08:27 +00:00 zatwierdzone przez GitHub
commit cb5db1d594
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
76 zmienionych plików z 1072 dodań i 1017 usunięć

Wyświetl plik

@ -1,172 +0,0 @@
name: MicroPython for Badger2040
on:
push:
pull_request:
release:
types: [created]
env:
MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096
BOARD_TYPE: PIMORONI_BADGER2040
# MicroPython version will be contained in github.event.release.tag_name for releases
RELEASE_FILE: pimoroni-badger2040-${{github.event.release.tag_name || github.sha}}-micropython
jobs:
deps:
runs-on: ubuntu-20.04
name: Dependencies
steps:
- name: Workspace Cache
id: cache
uses: actions/cache@v3
with:
path: ${{runner.workspace}}
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
restore-keys: |
workspace-micropython-${{env.MICROPYTHON_VERSION}}
# Check out MicroPython
- name: Checkout MicroPython
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v3
with:
repository: micropython/micropython
ref: ${{env.MICROPYTHON_VERSION}}
submodules: false # MicroPython submodules are hideously broken
path: micropython
- name: Fetch base MicroPython submodules
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython
run: git submodule update --init
- name: Fetch Pico SDK submodules
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython/lib/pico-sdk
run: git submodule update --init
- name: Build mpy-cross
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython/mpy-cross
run: make
build:
needs: deps
name: Build Badger 2040
runs-on: ubuntu-20.04
steps:
- name: Compiler Cache
uses: actions/cache@v3
with:
path: /home/runner/.ccache
key: ccache-micropython-badger2040-${{github.ref}}-${{github.sha}}
restore-keys: |
ccache-micropython-badger2040-${{github.ref}}
ccache-micropython-badger2040-
- name: Workspace Cache
uses: actions/cache@v3
with:
path: ${{runner.workspace}}
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
restore-keys: |
workspace-micropython-${{env.MICROPYTHON_VERSION}}
- uses: actions/checkout@v3
with:
submodules: true
path: pimoroni-pico-${{ github.sha }}
- name: "HACK: MicroPython Board Fixups"
shell: bash
working-directory: micropython/ports/rp2
run: |
../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040 ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board
# Linux deps
- name: Install Compiler & CCache
if: runner.os == 'Linux'
run: |
sudo apt update && sudo apt install ccache gcc-arm-none-eabi
python3 -m pip install pillow
# Build without BadgerOS
- name: Configure MicroPython (No BadgerOS)
shell: bash
working-directory: micropython/ports/rp2
run: |
cmake -S . -B build-${{env.BOARD_TYPE}}-without-badger-os -DBADGER2040_NO_MODULES=1 -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/badger2040-micropython.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build MicroPython (No BadgerOS)
shell: bash
working-directory: micropython/ports/rp2
run: |
ccache --zero-stats || true
cmake --build build-${{env.BOARD_TYPE}}-without-badger-os -j 2
ccache --show-stats || true
- name: Rename .uf2 for artifact (No BadgerOS)
shell: bash
working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os
run: |
cp firmware.uf2 ${{env.RELEASE_FILE}}-without-badger-os.uf2
- name: Store .uf2 as artifact (No BadgerOS)
uses: actions/upload-artifact@v3
with:
name: ${{env.RELEASE_FILE}}-without-badger-os.uf2
path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2
- name: Upload .uf2 (No BadgerOS)
if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2
upload_url: ${{github.event.release.upload_url}}
asset_name: ${{env.RELEASE_FILE}}-without-badger-os.uf2
asset_content_type: application/octet-stream
# Build with BadgerOS
- name: Configure MicroPython
shell: bash
working-directory: micropython/ports/rp2
run: |
cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/badger2040-micropython.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build MicroPython
shell: bash
working-directory: micropython/ports/rp2
run: |
ccache --zero-stats || true
cmake --build build-${{env.BOARD_TYPE}} -j 2
ccache --show-stats || true
- name: Rename .uf2 for artifact
shell: bash
working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}
run: |
cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2
- name: Store .uf2 as artifact
uses: actions/upload-artifact@v3
with:
name: ${{env.RELEASE_FILE}}.uf2
path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2
- name: Upload .uf2
if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2
upload_url: ${{github.event.release.upload_url}}
asset_name: ${{env.RELEASE_FILE}}.uf2
asset_content_type: application/octet-stream

Wyświetl plik

@ -1,164 +0,0 @@
name: MicroPython for Badger2040W
on:
push:
pull_request:
release:
types: [created]
env:
MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096
BOARD_TYPE: PIMORONI_BADGER2040W
# MicroPython version will be contained in github.event.release.tag_name for releases
RELEASE_FILE: pimoroni-badger2040w-${{github.event.release.tag_name || github.sha}}-micropython
jobs:
deps:
runs-on: ubuntu-20.04
name: Dependencies
steps:
- name: Workspace Cache
id: cache
uses: actions/cache@v3
with:
path: ${{runner.workspace}}
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
restore-keys: |
workspace-micropython-${{env.MICROPYTHON_VERSION}}
# Check out MicroPython
- name: Checkout MicroPython
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v3
with:
repository: micropython/micropython
ref: ${{env.MICROPYTHON_VERSION}}
submodules: false # MicroPython submodules are hideously broken
path: micropython
- name: Fetch base MicroPython submodules
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython
run: git submodule update --init
- name: Fetch Pico SDK submodules
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython/lib/pico-sdk
run: git submodule update --init
- name: Build mpy-cross
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
working-directory: micropython/mpy-cross
run: make
build:
needs: deps
name: Build Badger 2040W
runs-on: ubuntu-20.04
steps:
- name: Compiler Cache
uses: actions/cache@v3
with:
path: /home/runner/.ccache
key: ccache-micropython-badger2040w-${{github.ref}}-${{github.sha}}
restore-keys: |
ccache-micropython-badger2040w-${{github.ref}}
ccache-micropython-badger2040w-
- name: Workspace Cache
uses: actions/cache@v3
with:
path: ${{runner.workspace}}
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
restore-keys: |
workspace-micropython-${{env.MICROPYTHON_VERSION}}
- uses: actions/checkout@v3
with:
submodules: true
path: pimoroni-pico-${{ github.sha }}
# Check out dir2u2f
- uses: actions/checkout@v3
with:
repository: gadgetoid/dir2uf2
ref: v0.0.1
path: dir2uf2
- name: "HACK: MicroPython Board Fixups"
shell: bash
working-directory: micropython/ports/rp2
run: |
../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040w ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board
# Linux deps
- name: Install Compiler & CCache
if: runner.os == 'Linux'
run: |
sudo apt update && sudo apt install ccache gcc-arm-none-eabi
python3 -m pip install pillow
# Build firmware
- name: Configure MicroPython
shell: bash
working-directory: micropython/ports/rp2
run: |
cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build MicroPython
shell: bash
working-directory: micropython/ports/rp2
run: |
ccache --zero-stats || true
cmake --build build-${{env.BOARD_TYPE}} -j 2
ccache --show-stats || true
- name: Rename .uf2 for artifact
shell: bash
working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}
run: |
cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2
- name: Append Filesystem
shell: bash
run: |
python3 -m pip install littlefs-python
./dir2uf2/dir2uf2 --append-to micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 --manifest pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/uf2-manifest.txt --filename with-examples.uf2 pimoroni-pico-${{ github.sha }}/micropython/examples/badger2040w/
- name: Store .uf2 as artifact
uses: actions/upload-artifact@v3
with:
name: ${{env.RELEASE_FILE}}.uf2
path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2
- name: Store .uf2 + examples as artifact
uses: actions/upload-artifact@v3
with:
name: ${{env.RELEASE_FILE}}-with-examples.uf2
path: ${{env.RELEASE_FILE}}-with-examples.uf2
- name: Upload .uf2
if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2
upload_url: ${{github.event.release.upload_url}}
asset_name: ${{env.RELEASE_FILE}}.uf2
asset_content_type: application/octet-stream
- name: Upload .uf2 + examples
if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
asset_path: ${{env.RELEASE_FILE}}-with-examples.uf2
upload_url: ${{github.event.release.upload_url}}
asset_name: ${{env.RELEASE_FILE}}-with-examples.uf2
asset_content_type: application/octet-stream

Wyświetl plik

@ -7,7 +7,7 @@ on:
types: [created]
env:
MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096
MICROPYTHON_VERSION: 05bb26010e4a466a82cfed179f8d8d0b406a78ca
jobs:
deps:

Wyświetl plik

@ -7,7 +7,7 @@ on:
types: [created]
env:
MICROPYTHON_VERSION: 294098d28e2bad0ac0aad0d72595d11a82798096
MICROPYTHON_VERSION: 05bb26010e4a466a82cfed179f8d8d0b406a78ca
jobs:
deps:

Wyświetl plik

@ -11,7 +11,10 @@ namespace pimoroni {
gpio_pull_up(interrupt);
}
device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address};
i2c_interface.i2c = i2c;
i2c_interface.address = address;
device.intf_ptr = &i2c_interface;
device.intf = bme280_intf::BME280_I2C_INTF;
device.read = (bme280_read_fptr_t)&read_bytes;
device.write = (bme280_write_fptr_t)&write_bytes;

Wyświetl plik

@ -26,6 +26,8 @@ namespace pimoroni {
bool status;
};
i2c_intf_ptr i2c_interface;
bool debug = false;
bool init();

Wyświetl plik

@ -11,8 +11,10 @@ namespace pimoroni {
gpio_pull_up(interrupt);
}
device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address};
i2c_interface.i2c = i2c;
i2c_interface.address = address;
device.intf_ptr = &i2c_interface;
device.intf = bme68x_intf::BME68X_I2C_INTF;
device.read = (bme68x_read_fptr_t)&read_bytes;
device.write = (bme68x_write_fptr_t)&write_bytes;

Wyświetl plik

@ -18,6 +18,8 @@ namespace pimoroni {
int8_t address;
};
i2c_intf_ptr i2c_interface;
bool debug = true;
bool init();

Wyświetl plik

@ -11,7 +11,10 @@ namespace pimoroni {
gpio_pull_up(interrupt);
}
device.intf_ptr = new i2c_intf_ptr{.i2c = i2c, .address = address};
i2c_interface.i2c = i2c;
i2c_interface.address = address;
device.intf_ptr = &i2c_interface;
device.intf = BMP280_I2C_INTF;
device.read = (bmp280_com_fptr_t)&read_bytes;
device.write = (bmp280_com_fptr_t)&write_bytes;

Wyświetl plik

@ -25,6 +25,8 @@ namespace pimoroni {
bool status;
};
i2c_intf_ptr i2c_interface;
bool debug = false;
bool init();

Wyświetl plik

@ -29,8 +29,6 @@ namespace motor {
}
MotorCluster::~MotorCluster() {
delete[] states;
delete[] configs;
}
bool MotorCluster::init() {
@ -713,10 +711,8 @@ namespace motor {
float deadzone, DecayMode mode, bool auto_phase) {
uint8_t motor_count = pwms.get_chan_pair_count();
if(motor_count > 0) {
states = new MotorState[motor_count];
configs = new motor_config[motor_count];
for(uint motor = 0; motor < motor_count; motor++) {
configs[motor] = motor_config();
states[motor] = MotorState(direction, speed_scale, zeropoint, deadzone);
configs[motor].phase = (auto_phase) ? (float)motor / (float)motor_count : 0.0f;
configs[motor].mode = mode;

Wyświetl plik

@ -22,12 +22,15 @@ namespace motor {
//--------------------------------------------------
// Variables
//--------------------------------------------------
public:
static const uint MAX_MOTOR_CHANNELS = 16;
private:
PWMCluster pwms;
uint32_t pwm_period;
float pwm_frequency;
MotorState* states;
motor_config* configs;
MotorState states[MAX_MOTOR_CHANNELS];
motor_config configs[MAX_MOTOR_CHANNELS];
//--------------------------------------------------

Wyświetl plik

@ -27,7 +27,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_mask, bool loading_zone)
, sm(sm)
, pin_mask(pin_mask & ((1u << NUM_BANK0_GPIOS) - 1))
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -48,7 +47,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, bool loa
, sm(sm)
, pin_mask(0x00000000)
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -68,7 +66,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, b
, sm(sm)
, pin_mask(0x00000000)
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -90,7 +87,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list<uint8_t> pins, bo
, sm(sm)
, pin_mask(0x00000000)
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -111,7 +107,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t len
, sm(sm)
, pin_mask(0x00000000)
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -137,7 +132,6 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list<pin_pair> pin_pai
, sm(sm)
, pin_mask(0x00000000)
, channel_count(0)
, channels(nullptr)
, wrap_level(0)
, loading_zone(loading_zone) {
@ -159,8 +153,8 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list<pin_pair> pin_pai
void PWMCluster::constructor_common() {
// Initialise all the channels this PWM will control
if(channel_count > 0) {
channels = new ChannelState[channel_count];
for(uint i = 0; i < channel_count; i++) {
channels[i] = ChannelState();
}
// Set up the transition buffers
@ -216,8 +210,6 @@ PWMCluster::~PWMCluster() {
gpio_set_function(channel_to_pin_map[channel], GPIO_FUNC_NULL);
}
}
delete[] channels;
}
void PWMCluster::dma_interrupt_handler() {

Wyświetl plik

@ -24,6 +24,7 @@ namespace pimoroni {
public:
static const uint BUFFER_SIZE = 64; // Set to 64, the maximum number of single rises and falls for 32 channels within a looping time period
static const uint NUM_BUFFERS = 3;
static const uint MAX_PWM_CHANNELS = 32;
//--------------------------------------------------
@ -104,7 +105,7 @@ namespace pimoroni {
int dma_channel;
uint pin_mask;
uint8_t channel_count;
ChannelState* channels;
ChannelState channels[NUM_BANK0_GPIOS];
uint8_t channel_to_pin_map[NUM_BANK0_GPIOS];
uint wrap_level;

Wyświetl plik

@ -10,7 +10,7 @@ namespace servo {
}
Calibration::Calibration()
: calibration(nullptr), calibration_size(0), limit_lower(true), limit_upper(true) {
: calibration_size(0), limit_lower(true), limit_upper(true) {
}
Calibration::Calibration(CalibrationType default_type)
@ -19,7 +19,7 @@ namespace servo {
}
Calibration::Calibration(const Calibration &other)
: calibration(nullptr), calibration_size(0), limit_lower(other.limit_lower), limit_upper(other.limit_upper) {
: calibration_size(0), limit_lower(other.limit_lower), limit_upper(other.limit_upper) {
uint size = other.size();
apply_blank_pairs(size);
for(uint i = 0; i < size; i++) {
@ -28,10 +28,6 @@ namespace servo {
}
Calibration::~Calibration() {
if(calibration != nullptr) {
delete[] calibration;
calibration = nullptr;
}
}
Calibration &Calibration::operator=(const Calibration &other) {
@ -57,16 +53,13 @@ namespace servo {
}
void Calibration::apply_blank_pairs(uint size) {
if(calibration != nullptr) {
delete[] calibration;
}
if(size > 0) {
calibration = new Pair[size];
for(auto i = 0u; i < size; i++) {
calibration[i] = Pair();
}
calibration_size = size;
}
else {
calibration = nullptr;
calibration_size = 0;
}
}

Wyświetl plik

@ -19,6 +19,8 @@ namespace servo {
static constexpr float DEFAULT_MID_PULSE = 1500.0f; // in microseconds
static constexpr float DEFAULT_MAX_PULSE = 2500.0f; // in microseconds
static const uint MAX_CALIBRATION_PAIRS = 32;
private:
static constexpr float LOWER_HARD_LIMIT = 400.0f; // The minimum microsecond pulse to send
static constexpr float UPPER_HARD_LIMIT = 2600.0f; // The maximum microsecond pulse to send
@ -110,7 +112,7 @@ namespace servo {
// Variables
//--------------------------------------------------
private:
Pair* calibration;
Pair calibration[MAX_CALIBRATION_PAIRS];
uint calibration_size;
bool limit_lower;
bool limit_upper;

Wyświetl plik

@ -44,8 +44,6 @@ namespace servo {
}
ServoCluster::~ServoCluster() {
delete[] states;
delete[] servo_phases;
}
bool ServoCluster::init() {
@ -502,9 +500,6 @@ namespace servo {
void ServoCluster::create_servo_states(CalibrationType default_type, bool auto_phase) {
uint8_t servo_count = pwms.get_chan_count();
if(servo_count > 0) {
states = new ServoState[servo_count];
servo_phases = new float[servo_count];
for(uint servo = 0; servo < servo_count; servo++) {
states[servo] = ServoState(default_type);
servo_phases[servo] = (auto_phase) ? (float)servo / (float)servo_count : 0.0f;
@ -515,9 +510,6 @@ namespace servo {
void ServoCluster::create_servo_states(const Calibration& calibration, bool auto_phase) {
uint8_t servo_count = pwms.get_chan_count();
if(servo_count > 0) {
states = new ServoState[servo_count];
servo_phases = new float[servo_count];
for(uint servo = 0; servo < servo_count; servo++) {
states[servo] = ServoState(calibration);
servo_phases[servo] = (auto_phase) ? (float)servo / (float)servo_count : 0.0f;

Wyświetl plik

@ -12,12 +12,14 @@ namespace servo {
//--------------------------------------------------
// Variables
//--------------------------------------------------
public:
static const uint MAX_SERVO_CHANNELS = 32;
private:
PWMCluster pwms;
uint32_t pwm_period;
float pwm_frequency;
ServoState* states;
float* servo_phases;
ServoState states[MAX_SERVO_CHANNELS];
float servo_phases[MAX_SERVO_CHANNELS];
//--------------------------------------------------

Wyświetl plik

@ -4,7 +4,7 @@ add_executable(
)
# Pull in pico libraries that we need
target_link_libraries(unicorn pico_stdlib hardware_pio hardware_dma pico_unicorn)
target_link_libraries(unicorn pico_stdlib hardware_pio hardware_dma pico_graphics pico_unicorn)
# create map/bin/hex file etc.
pico_add_extra_outputs(unicorn)

Wyświetl plik

@ -10,9 +10,6 @@ using namespace pimoroni;
PicoUnicorn pico_unicorn;
int main() {
pico_unicorn.init();
bool a_pressed = false;
bool b_pressed = false;
bool x_pressed = false;

Wyświetl plik

@ -8,7 +8,7 @@ pico_enable_stdio_usb(unicornplasma 1)
pico_enable_stdio_uart(unicornplasma 1)
# Pull in pico libraries that we need
target_link_libraries(unicornplasma pico_stdlib hardware_pio hardware_dma pico_unicorn)
target_link_libraries(unicornplasma pico_stdlib hardware_pio hardware_dma pico_graphics pico_unicorn)
# create map/bin/hex file etc.
pico_add_extra_outputs(unicornplasma)

Wyświetl plik

@ -21,7 +21,7 @@ namespace bitmap {
return font->widths[char_index] * scale;
}
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale, const uint8_t letter_spacing) {
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale, const uint8_t letter_spacing) {
int32_t text_width = 0;
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;
for(auto c : t) {
@ -119,7 +119,7 @@ namespace bitmap {
}
}
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing) {
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing) {
uint32_t co = 0, lo = 0; // character and line (if wrapping) offset
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;

Wyświetl plik

@ -2,6 +2,7 @@
#include <functional>
#include <string>
#include <string_view>
#include <cstdint>
#include "common/unicode_sorta.hpp"
@ -19,8 +20,8 @@ namespace bitmap {
typedef std::function<void(int32_t x, int32_t y, int32_t w, int32_t h)> rect_func;
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
}

Wyświetl plik

@ -14,6 +14,26 @@ namespace hershey {
//{ "serif_bold", &timesrb }
};
bool has_font(std::string_view font) {
if(font == "sans"
|| font == "gothic"
|| font == "cursive"
|| font == "serif_italic"
|| font == "serif") {
return true;
}
return false;
}
const font_t* font(std::string_view font) {
if(font == "sans") return &futural;
else if(font == "gothic") return &gothgbt;
else if(font == "cursive") return &scripts;
else if(font == "serif_italic") return &timesi;
else if(font == "serif") return &timesr;
return &futural;
}
inline float deg2rad(float degrees) {
return (degrees * M_PI) / 180.0f;
}
@ -41,7 +61,7 @@ namespace hershey {
return gd->width * s;
}
int32_t measure_text(const font_t* font, std::string message, float s) {
int32_t measure_text(const font_t* font, std::string_view message, float s) {
int32_t width = 0;
for(auto &c : message) {
width += measure_glyph(font, c, s);
@ -93,7 +113,7 @@ namespace hershey {
return gd->width * s;
}
void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a) {
void text(const font_t* font, line_func line, std::string_view message, int32_t x, int32_t y, float s, float a) {
int32_t cx = x;
int32_t cy = y;

Wyświetl plik

@ -44,7 +44,10 @@ namespace hershey {
inline float deg2rad(float degrees);
const font_glyph_t* glyph_data(const font_t* font, unsigned char c);
int32_t measure_glyph(const font_t* font, unsigned char c, float s);
int32_t measure_text(const font_t* font, std::string message, float s);
int32_t measure_text(const font_t* font, std::string_view message, float s);
int32_t glyph(const font_t* font, line_func line, unsigned char c, int32_t x, int32_t y, float s, float a);
void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a);
void text(const font_t* font, line_func line, std::string_view message, int32_t x, int32_t y, float s, float a);
bool has_font(std::string_view font);
const font_t* font(std::string_view font);
}

Wyświetl plik

@ -35,7 +35,7 @@ namespace pimoroni {
this->hershey_font = font;
}
void PicoGraphics::set_font(std::string name){
void PicoGraphics::set_font(std::string_view name){
if (name == "bitmap6") {
set_font(&font6);
} else if (name == "bitmap8") {
@ -44,8 +44,8 @@ namespace pimoroni {
set_font(&font14_outline);
} else {
// check that font exists and assign it
if(hershey::fonts.find(name) != hershey::fonts.end()) {
set_font(hershey::fonts[name]);
if(hershey::has_font(name)) {
set_font(hershey::font(name));
}
}
}
@ -144,7 +144,7 @@ namespace pimoroni {
}
}
void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) {
void PicoGraphics::text(const std::string_view &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) {
if (bitmap_font) {
bitmap::text(bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) {
rectangle(Rect(x, y, w, h));
@ -166,7 +166,7 @@ namespace pimoroni {
}
}
int32_t PicoGraphics::measure_text(const std::string &t, float s, uint8_t letter_spacing) {
int32_t PicoGraphics::measure_text(const std::string_view &t, float s, uint8_t letter_spacing) {
if (bitmap_font) return bitmap::measure_text(bitmap_font, t, std::max(1.0f, s), letter_spacing);
if (hershey_font) return hershey::measure_text(hershey_font, t, s);
return 0;

Wyświetl plik

@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <string_view>
#include <array>
#include <cstdint>
#include <algorithm>
@ -268,7 +269,7 @@ namespace pimoroni {
void set_font(const bitmap::font_t *font);
void set_font(const hershey::font_t *font);
void set_font(std::string font);
void set_font(std::string_view name);
void set_dimensions(int width, int height);
void set_framebuffer(void *frame_buffer);
@ -285,8 +286,8 @@ namespace pimoroni {
void rectangle(const Rect &r);
void circle(const Point &p, int32_t r);
void character(const char c, const Point &p, float s = 2.0f, float a = 0.0f);
void text(const std::string &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1);
int32_t measure_text(const std::string &t, float s = 2.0f, uint8_t letter_spacing = 1);
void text(const std::string_view &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1);
int32_t measure_text(const std::string_view &t, float s = 2.0f, uint8_t letter_spacing = 1);
void polygon(const std::vector<Point> &points);
void triangle(Point p1, Point p2, Point p3);
void line(Point p1, Point p2);

Wyświetl plik

@ -17,6 +17,11 @@ enum pin {
namespace pimoroni {
PicoRGBKeypad::~PicoRGBKeypad() {
clear();
update();
}
void PicoRGBKeypad::init() {
memset(buffer, 0, sizeof(buffer));
led_data = buffer + 4;

Wyświetl plik

@ -16,6 +16,7 @@ namespace pimoroni {
uint8_t *led_data;
public:
~PicoRGBKeypad();
void init();
void update();
void set_brightness(float brightness);

Wyświetl plik

@ -11,4 +11,4 @@ target_sources(pico_scroll INTERFACE
target_include_directories(pico_scroll INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(pico_scroll INTERFACE pico_stdlib hardware_i2c)
target_link_libraries(pico_scroll INTERFACE pico_stdlib pico_graphics hardware_i2c)

Wyświetl plik

@ -35,6 +35,11 @@ enum reg {
namespace pimoroni {
PicoScroll::~PicoScroll() {
clear();
update();
}
void PicoScroll::init() {
// setup i2c interface
i2c_init(i2c0, 400000);
@ -166,4 +171,61 @@ namespace pimoroni {
memcpy(&buffer[1], data, len);
i2c_write_blocking(i2c0, DEFAULT_ADDRESS, buffer, len + 1, true);
}
void PicoScroll::update(PicoGraphics *graphics) {
if(graphics->pen_type == PicoGraphics::PEN_RGB888) {
uint32_t *p = (uint32_t *)graphics->frame_buffer;
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
uint32_t col = *p;
uint8_t r = (col & 0xff0000) >> 16;
uint8_t g = (col & 0x00ff00) >> 8;
uint8_t b = (col & 0x0000ff) >> 0;
p++;
set_pixel(x, y, (r + g + b) / 3);
}
}
update();
}
else if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
uint16_t *p = (uint16_t *)graphics->frame_buffer;
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
uint16_t col = __builtin_bswap16(*p);
uint8_t r = (col & 0b1111100000000000) >> 8;
uint8_t g = (col & 0b0000011111100000) >> 3;
uint8_t b = (col & 0b0000000000011111) << 3;
p++;
set_pixel(x, y, (r + g + b) / 3);
}
}
update();
}
else if(graphics->pen_type == PicoGraphics::PEN_P8 || graphics->pen_type == PicoGraphics::PEN_P4) {
int offset = 0;
graphics->frame_convert(PicoGraphics::PEN_RGB888, [this, offset](void *data, size_t length) mutable {
uint32_t *p = (uint32_t *)data;
for(auto i = 0u; i < length / 4; i++) {
int x = offset % WIDTH;
int y = offset / WIDTH;
uint32_t col = *p;
uint8_t r = (col & 0xff0000) >> 16;
uint8_t g = (col & 0x00ff00) >> 8;
uint8_t b = (col & 0x0000ff) >> 0;
set_pixel(x, y, (r + g + b) / 3);
offset++;
p++;
}
});
update();
}
}
}

Wyświetl plik

@ -1,6 +1,8 @@
#include <string>
#pragma once
#include <string>
#include "pico_graphics.hpp"
namespace pimoroni {
class PicoScroll {
@ -19,6 +21,7 @@ namespace pimoroni {
uint8_t __fb[BUFFER_SIZE];
public:
~PicoScroll();
void init();
void update();
void set_pixels(const char *pixels);
@ -35,6 +38,7 @@ namespace pimoroni {
void clear();
bool is_pressed(uint8_t button);
void update(PicoGraphics *graphics);
private:
void i2c_write(uint8_t reg, const char *data, uint8_t len);
};

Wyświetl plik

@ -1,4 +1,5 @@
#include "pico_scroll_font.hpp"
#include <string.h>
/* static font data */
static const unsigned char __bitmap[256][5] = {
@ -135,13 +136,15 @@ static const unsigned char __bitmap[256][5] = {
/* render a text string to a pre-allocated buffer - strlen(text) * 6 bytes */
int render_text(const char *text, unsigned int nchr, unsigned char *buffer, unsigned int nbfr) {
// TODO check nbfr >= 6 * nchr
memset(buffer, 0, nbfr);
for (unsigned int i = 0; i < nchr; i++) {
const unsigned char *symbol = __bitmap[(unsigned int)text[i]];
for (unsigned int j = 0; j < 5; j++) {
buffer[i * 6 + j] = symbol[j];
unsigned int offset = i * 6 + j;
if (offset >= nbfr) return -1;
buffer[offset] = symbol[j];
}
buffer[i * 6 + 5] = 0x0;
}
return 0;
}

Wyświetl plik

@ -12,13 +12,12 @@ We've included helper functions to handle every aspect of drawing to the display
- [Buttons](#buttons)
- [WIDTH / HEIGHT](#width--height)
- [Functions](#functions)
- [init](#init)
- [set_pixel](#set_pixel)
- [is_pressed](#is_pressed)
- [set\_pixel](#set_pixel)
- [is\_pressed](#is_pressed)
## Example Program
The following example sets up Pico Unicorn, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is presse
The following example sets up Pico Unicorn, displays some basic demo text and graphics and will illuminate the RGB LED green if the A button is pressed.
```c++
@ -48,15 +47,6 @@ int num_pixels = pico_unicorn.WIDTH * pico_unicorn.HEIGHT;
### Functions
#### init
Sets up Pico Unicorn. `init` must be called before any other functions since it configures the PIO and require GPIO inputs. Just call `init()` like so:
```c++
PicoUnicorn pico_unicorn;
pico_unicorn.init();
```
#### set_pixel
```c++

Wyświetl plik

@ -9,4 +9,4 @@ target_sources(pico_unicorn INTERFACE
target_include_directories(pico_unicorn INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(pico_unicorn INTERFACE pico_stdlib hardware_pio hardware_dma)
target_link_libraries(pico_unicorn INTERFACE pico_stdlib pico_graphics hardware_pio hardware_dma)

Wyświetl plik

@ -44,82 +44,53 @@ enum pin {
Y = 15,
};
constexpr uint32_t ROW_COUNT = 7;
constexpr uint32_t ROW_BYTES = 12;
constexpr uint32_t BCD_FRAMES = 15; // includes fet discharge frame
constexpr uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES * BCD_FRAMES);
// must be aligned for 32bit dma transfer
alignas(4) static uint8_t bitstream[BITSTREAM_LENGTH] = {0};
static uint32_t dma_channel;
static inline void unicorn_jetpack_program_init(PIO pio, uint sm, uint offset) {
pio_gpio_init(pio, pin::LED_DATA);
pio_gpio_init(pio, pin::LED_CLOCK);
pio_gpio_init(pio, pin::LED_LATCH);
pio_gpio_init(pio, pin::LED_BLANK);
pio_gpio_init(pio, pin::ROW_0);
pio_gpio_init(pio, pin::ROW_1);
pio_gpio_init(pio, pin::ROW_2);
pio_gpio_init(pio, pin::ROW_3);
pio_gpio_init(pio, pin::ROW_4);
pio_gpio_init(pio, pin::ROW_5);
pio_gpio_init(pio, pin::ROW_6);
pio_sm_set_consecutive_pindirs(pio, sm, pin::LED_DATA, 4, true);
pio_sm_set_consecutive_pindirs(pio, sm, pin::ROW_6, 7, true);
pio_sm_config c = unicorn_program_get_default_config(offset);
// osr shifts right, autopull on, autopull threshold 8
sm_config_set_out_shift(&c, true, false, 32);
// configure out, set, and sideset pins
sm_config_set_out_pins(&c, pin::ROW_6, 7);
sm_config_set_sideset_pins(&c, pin::LED_CLOCK);
sm_config_set_set_pins(&c, pin::LED_DATA, 4);
// join fifos as only tx needed (gives 8 deep fifo instead of 4)
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static uint32_t dma_ctrl_channel;
namespace pimoroni {
PicoUnicorn* PicoUnicorn::unicorn = nullptr;
PIO PicoUnicorn::bitstream_pio = pio0;
uint PicoUnicorn::bitstream_sm = 0;
uint PicoUnicorn::bitstream_sm_offset = 0;
// once the dma transfer of the scanline is complete we move to the
// next scanline (or quit if we're finished)
void __isr dma_complete() {
if (dma_hw->ints0 & (1u << dma_channel)) {
dma_hw->ints0 = (1u << dma_channel); // clear irq flag
dma_channel_set_trans_count(dma_channel, BITSTREAM_LENGTH / 4, false);
dma_channel_set_read_addr(dma_channel, bitstream, true);
PicoUnicorn::~PicoUnicorn() {
if(unicorn == this) {
partial_teardown();
dma_channel_unclaim(dma_ctrl_channel); // This works now the teardown behaves correctly
dma_channel_unclaim(dma_channel); // This works now the teardown behaves correctly
pio_sm_unclaim(bitstream_pio, bitstream_sm);
pio_remove_program(bitstream_pio, &unicorn_program, bitstream_sm_offset);
unicorn = nullptr;
}
}
PicoUnicorn::~PicoUnicorn() {
// stop and release the dma channel
irq_set_enabled(DMA_IRQ_0, false);
dma_channel_set_irq0_enabled(dma_channel, false);
irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), false);
irq_remove_handler(DMA_IRQ_0, dma_complete);
void PicoUnicorn::partial_teardown() {
// Stop the bitstream SM
pio_sm_set_enabled(bitstream_pio, bitstream_sm, false);
dma_channel_wait_for_finish_blocking(dma_channel);
dma_channel_unclaim(dma_channel);
// Make sure the display is off and switch it to an invisible row, to be safe
const uint pins_to_set = 0b1111111 << ROW_6;
pio_sm_set_pins_with_mask(bitstream_pio, bitstream_sm, pins_to_set, pins_to_set);
// release the pio and sm
pio_sm_unclaim(bitstream_pio, bitstream_sm);
pio_clear_instruction_memory(bitstream_pio);
pio_sm_restart(bitstream_pio, bitstream_sm);
dma_hw->ch[dma_ctrl_channel].al1_ctrl = (dma_hw->ch[dma_ctrl_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_ctrl_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
dma_hw->ch[dma_channel].al1_ctrl = (dma_hw->ch[dma_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
// Abort any in-progress DMA transfer
dma_safe_abort(dma_ctrl_channel);
dma_safe_abort(dma_channel);
}
[[deprecated("Handled by constructor.")]]
void PicoUnicorn::init() {
// todo: shouldn't need to do this if things were cleaned up properly but without
// this any attempt to run a micropython script twice will fail
static bool already_init = false;
return;
}
PicoUnicorn::PicoUnicorn() {
if(unicorn != nullptr) {
partial_teardown();
}
// setup pins
gpio_init(pin::LED_DATA); gpio_set_dir(pin::LED_DATA, GPIO_OUT);
gpio_init(pin::LED_CLOCK); gpio_set_dir(pin::LED_CLOCK, GPIO_OUT);
@ -171,47 +142,81 @@ namespace pimoroni {
gpio_set_function(pin::X, GPIO_FUNC_SIO); gpio_set_dir(pin::X, GPIO_IN); gpio_pull_up(pin::X);
gpio_set_function(pin::Y, GPIO_FUNC_SIO); gpio_set_dir(pin::Y, GPIO_IN); gpio_pull_up(pin::Y);
if(already_init) {
// stop and release the dma channel
irq_set_enabled(DMA_IRQ_0, false);
dma_channel_abort(dma_channel);
dma_channel_wait_for_finish_blocking(dma_channel);
dma_channel_set_irq0_enabled(dma_channel, false);
irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), false);
irq_remove_handler(DMA_IRQ_0, dma_complete);
dma_channel_unclaim(dma_channel);
// release the pio and sm
pio_sm_unclaim(bitstream_pio, bitstream_sm);
pio_clear_instruction_memory(bitstream_pio);
pio_sm_restart(bitstream_pio, bitstream_sm);
//return;
}
// setup the pio
bitstream_pio = pio0;
bitstream_sm = pio_claim_unused_sm(pio0, true);
sm_offset = pio_add_program(bitstream_pio, &unicorn_program);
unicorn_jetpack_program_init(bitstream_pio, bitstream_sm, sm_offset);
if(unicorn == nullptr) {
bitstream_sm = pio_claim_unused_sm(bitstream_pio, true);
bitstream_sm_offset = pio_add_program(bitstream_pio, &unicorn_program);
}
pio_gpio_init(bitstream_pio, pin::LED_DATA);
pio_gpio_init(bitstream_pio, pin::LED_CLOCK);
pio_gpio_init(bitstream_pio, pin::LED_LATCH);
pio_gpio_init(bitstream_pio, pin::LED_BLANK);
pio_gpio_init(bitstream_pio, pin::ROW_0);
pio_gpio_init(bitstream_pio, pin::ROW_1);
pio_gpio_init(bitstream_pio, pin::ROW_2);
pio_gpio_init(bitstream_pio, pin::ROW_3);
pio_gpio_init(bitstream_pio, pin::ROW_4);
pio_gpio_init(bitstream_pio, pin::ROW_5);
pio_gpio_init(bitstream_pio, pin::ROW_6);
// setup dma transfer for pixel data to the pio
pio_sm_set_consecutive_pindirs(bitstream_pio, bitstream_sm, pin::LED_DATA, 4, true);
pio_sm_set_consecutive_pindirs(bitstream_pio, bitstream_sm, pin::ROW_6, 7, true);
pio_sm_config c = unicorn_program_get_default_config(bitstream_sm_offset);
// osr shifts right, autopull on, autopull threshold 8
sm_config_set_out_shift(&c, true, false, 32);
// configure out, set, and sideset pins
sm_config_set_out_pins(&c, pin::ROW_6, 7);
sm_config_set_sideset_pins(&c, pin::LED_CLOCK);
sm_config_set_set_pins(&c, pin::LED_DATA, 4);
// join fifos as only tx needed (gives 8 deep fifo instead of 4)
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// setup chained dma transfer for pixel data to the pio
dma_channel = dma_claim_unused_channel(true);
dma_ctrl_channel = dma_claim_unused_channel(true);
dma_channel_config ctrl_config = dma_channel_get_default_config(dma_ctrl_channel);
channel_config_set_transfer_data_size(&ctrl_config, DMA_SIZE_32);
channel_config_set_read_increment(&ctrl_config, false);
channel_config_set_write_increment(&ctrl_config, false);
channel_config_set_chain_to(&ctrl_config, dma_channel);
dma_channel_configure(
dma_ctrl_channel,
&ctrl_config,
&dma_hw->ch[dma_channel].read_addr,
&bitstream_addr,
1,
false
);
dma_channel_config config = dma_channel_get_default_config(dma_channel);
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
channel_config_set_bswap(&config, false); // byte swap to reverse little endian
channel_config_set_dreq(&config, pio_get_dreq(bitstream_pio, bitstream_sm, true));
dma_channel_configure(dma_channel, &config, &bitstream_pio->txf[bitstream_sm], NULL, 0, false);
dma_channel_set_irq0_enabled(dma_channel, true);
irq_set_enabled(pio_get_dreq(bitstream_pio, bitstream_sm, true), true);
irq_set_exclusive_handler(DMA_IRQ_0, dma_complete);
irq_set_enabled(DMA_IRQ_0, true);
channel_config_set_chain_to(&config, dma_ctrl_channel);
dma_channel_set_trans_count(dma_channel, BITSTREAM_LENGTH / 4, false);
dma_channel_set_read_addr(dma_channel, bitstream, true);
dma_channel_configure(
dma_channel,
&config,
&bitstream_pio->txf[bitstream_sm],
NULL,
BITSTREAM_LENGTH / 4,
false);
already_init = true;
pio_sm_init(bitstream_pio, bitstream_sm, bitstream_sm_offset, &c);
pio_sm_set_enabled(bitstream_pio, bitstream_sm, true);
// start the control channel
dma_start_channel_mask(1u << dma_ctrl_channel);
unicorn = this;
}
void PicoUnicorn::clear() {
@ -269,4 +274,74 @@ namespace pimoroni {
return !gpio_get(button);
}
void PicoUnicorn::dma_safe_abort(uint channel) {
// Tear down the DMA channel.
// This is copied from: https://github.com/raspberrypi/pico-sdk/pull/744/commits/5e0e8004dd790f0155426e6689a66e08a83cd9fc
uint32_t irq0_save = dma_hw->inte0 & (1u << channel);
hw_clear_bits(&dma_hw->inte0, irq0_save);
dma_hw->abort = 1u << channel;
// To fence off on in-flight transfers, the BUSY bit should be polled
// rather than the ABORT bit, because the ABORT bit can clear prematurely.
while (dma_hw->ch[channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents();
// Clear the interrupt (if any) and restore the interrupt masks.
dma_hw->ints0 = 1u << channel;
hw_set_bits(&dma_hw->inte0, irq0_save);
}
void PicoUnicorn::update(PicoGraphics *graphics) {
if(unicorn == this) {
if(graphics->pen_type == PicoGraphics::PEN_RGB888) {
uint32_t *p = (uint32_t *)graphics->frame_buffer;
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
uint32_t col = *p;
uint8_t r = (col & 0xff0000) >> 16;
uint8_t g = (col & 0x00ff00) >> 8;
uint8_t b = (col & 0x0000ff) >> 0;
p++;
set_pixel(x, y, r, g, b);
}
}
}
else if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
uint16_t *p = (uint16_t *)graphics->frame_buffer;
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
uint16_t col = __builtin_bswap16(*p);
uint8_t r = (col & 0b1111100000000000) >> 8;
uint8_t g = (col & 0b0000011111100000) >> 3;
uint8_t b = (col & 0b0000000000011111) << 3;
p++;
set_pixel(x, y, r, g, b);
}
}
}
else if(graphics->pen_type == PicoGraphics::PEN_P8 || graphics->pen_type == PicoGraphics::PEN_P4) {
int offset = 0;
graphics->frame_convert(PicoGraphics::PEN_RGB888, [this, offset](void *data, size_t length) mutable {
uint32_t *p = (uint32_t *)data;
for(auto i = 0u; i < length / 4; i++) {
int x = offset % WIDTH;
int y = offset / WIDTH;
uint32_t col = *p;
uint8_t r = (col & 0xff0000) >> 16;
uint8_t g = (col & 0x00ff00) >> 8;
uint8_t b = (col & 0x0000ff) >> 0;
set_pixel(x, y, r, g, b);
offset++;
p++;
}
});
}
}
}
}

Wyświetl plik

@ -1,6 +1,7 @@
#pragma once
#include "hardware/pio.h"
#include "pico_graphics.hpp"
namespace pimoroni {
@ -12,11 +13,24 @@ namespace pimoroni {
static const uint8_t B = 13;
static const uint8_t X = 14;
static const uint8_t Y = 15;
static const uint32_t ROW_COUNT = 7;
static const uint32_t ROW_BYTES = 12;
static const uint32_t BCD_FRAMES = 15; // includes fet discharge frame
static const uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES * BCD_FRAMES);
private:
PIO bitstream_pio = pio0;
uint bitstream_sm = 0;
uint sm_offset = 0;
static PIO bitstream_pio;
static uint bitstream_sm;
static uint bitstream_sm_offset;
// must be aligned for 32bit dma transfer
alignas(4) uint8_t bitstream[BITSTREAM_LENGTH] = {0};
const uint32_t bitstream_addr = (uint32_t)bitstream;
static PicoUnicorn* unicorn;
public:
PicoUnicorn();
~PicoUnicorn();
void init();
@ -26,6 +40,11 @@ namespace pimoroni {
void set_pixel(uint8_t x, uint8_t y, uint8_t v);
bool is_pressed(uint8_t button);
void update(PicoGraphics *graphics);
private:
void partial_teardown();
void dma_safe_abort(uint channel);
};
}

Wyświetl plik

@ -1,7 +1,7 @@
import time
import picokeypad as keypad
import picokeypad
keypad.init()
keypad = picokeypad.PicoKeypad()
keypad.set_brightness(1.0)
lit = 0

Wyświetl plik

@ -1,30 +1,28 @@
import time
import picoscroll as scroll
from picoscroll import PicoScroll, WIDTH, HEIGHT
scroll = PicoScroll()
scroll.init()
i = 0
loop = 18
br_mult = 1
br_pressed = 32
tail = 12
width = scroll.get_width()
height = scroll.get_height()
while True:
scroll.clear()
for y in range(0, height):
for x in range(0, width):
for y in range(0, HEIGHT):
for x in range(0, WIDTH):
if x < 3 and y < 3 and scroll.is_pressed(scroll.BUTTON_A):
scroll.set_pixel(x, y, br_pressed)
elif x < 3 and y > 3 and scroll.is_pressed(scroll.BUTTON_B):
scroll.set_pixel(x, y, br_pressed)
elif x > width - 4 and y < 3 and scroll.is_pressed(scroll.BUTTON_X):
elif x > WIDTH - 4 and y < 3 and scroll.is_pressed(scroll.BUTTON_X):
scroll.set_pixel(x, y, br_pressed)
elif x > width - 4 and y > 3 and scroll.is_pressed(scroll.BUTTON_Y):
elif x > WIDTH - 4 and y > 3 and scroll.is_pressed(scroll.BUTTON_Y):
scroll.set_pixel(x, y, br_pressed)
else:
m = (x + (y * width)) % loop
m = (x + (y * WIDTH)) % loop
for b in range(0, loop):
if m == (i + (loop - b)) % loop and b < tail:
scroll.set_pixel(x, y, br_mult * (tail - b))

Wyświetl plik

@ -0,0 +1,24 @@
from picographics import PicoGraphics, DISPLAY_SCROLL_PACK, PEN_P8
from picoscroll import PicoScroll
import time
TEXT = "Hello World"
# By default P8 has a greyscale palette
graphics = PicoGraphics(DISPLAY_SCROLL_PACK, pen_type=PEN_P8)
scroll = PicoScroll()
t = scroll.get_width()
wrap = -graphics.measure_text(TEXT, scale=0)
while True:
graphics.set_pen(0)
graphics.clear()
graphics.set_pen(255)
graphics.text(TEXT, t, 0, scale=1)
scroll.update(graphics)
t -= 1
time.sleep(0.1)
if t <= wrap:
t = scroll.get_width()

Wyświetl plik

@ -1,7 +1,7 @@
import time
import picoscroll as scroll
from picoscroll import PicoScroll
scroll.init()
scroll = PicoScroll()
while True:
scroll.scroll_text("Hello World", 128, 80)

Wyświetl plik

@ -1,6 +1,6 @@
import picounicorn
from picounicorn import PicoUnicorn
picounicorn.init()
picounicorn = PicoUnicorn()
# From CPython Lib/colorsys.py

Wyświetl plik

@ -1,7 +1,7 @@
import picounicorn
from picounicorn import PicoUnicorn
import time
picounicorn.init()
picounicorn = PicoUnicorn()
# From CPython Lib/colorsys.py

Wyświetl plik

@ -3,6 +3,9 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/../../)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -48,11 +48,15 @@ mp_obj_t BreakoutBME280_read(mp_obj_t self_in) {
breakout_bme280_BreakoutBME280_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_bme280_BreakoutBME280_obj_t);
BME280::bme280_reading result = self->breakout->read_forced();
mp_obj_t tuple[3];
tuple[0] = mp_obj_new_float(result.temperature);
tuple[1] = mp_obj_new_float(result.pressure);
tuple[2] = mp_obj_new_float(result.humidity);
return mp_obj_new_tuple(3, tuple);
if(result.status) {
mp_obj_t tuple[3];
tuple[0] = mp_obj_new_float(result.temperature);
tuple[1] = mp_obj_new_float(result.pressure);
tuple[2] = mp_obj_new_float(result.humidity);
return mp_obj_new_tuple(3, tuple);
}
mp_raise_msg(&mp_type_RuntimeError, "BME280: read failed.");
}
mp_obj_t BreakoutBME280_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {

Wyświetl plik

@ -247,10 +247,8 @@ mp_obj_t _JPEG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
if(mp_obj_is_str_or_bytes(self->file)){
GET_STR_DATA_LEN(self->file, str, str_len);
std::string t((const char*)str);
result = self->jpeg->open(
t.c_str(),
(const char*)str,
jpegdec_open_callback,
jpegdec_close_callback,
jpegdec_read_callback,

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -1,31 +1,43 @@
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)
# Pico Graphics Essential
include(hershey_fonts/micropython)
include(bitmap_fonts/micropython)
include(picographics/micropython)
# Pico Graphics Extra
include(jpegdec/micropython)
include(qrcode/micropython/micropython)
# Sensors & Breakouts
include(micropython-common-breakouts)
# Packs & Bases
include(pico_unicorn/micropython)
include(pico_scroll/micropython)
include(pico_rgb_keypad/micropython)
include(pico_unicorn/micropython)
include(pico_wireless/micropython)
include(pico_explorer/micropython)
include(hershey_fonts/micropython)
include(bitmap_fonts/micropython)
# LEDs & Matrices
include(plasma/micropython)
include(hub75/micropython)
# Servos & Motors
include(pwm/micropython)
include(servo/micropython)
include(encoder/micropython)
include(motor/micropython)
include(qrcode/micropython/micropython)
# Utility
include(adcfft/micropython)
include(pcf85063a/micropython)
include(picographics/micropython)
include(jpegdec/micropython)
include(galactic_unicorn/micropython)
# RTC (Badger 2040W, Enviro)
if(PICO_BOARD STREQUAL "pico_w")
include(pcf85063a/micropython)
endif()
include(modules_py/modules_py)
@ -37,4 +49,5 @@ if(PICO_BOARD STREQUAL "pico_w")
copy_module(inventor.py)
endif()
# Must call `enable_ulab()` to enable
include(micropython-common-ulab)

Wyświetl plik

@ -4,4 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(micropython-common)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(micropython-common)
enable_ulab()

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(micropython-common)
enable_ulab()

Wyświetl plik

@ -4,41 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Pico Graphics Essential
include(hershey_fonts/micropython)
include(bitmap_fonts/micropython)
include(picographics/micropython)
# Pico Graphics Extra
include(jpegdec/micropython)
include(qrcode/micropython/micropython)
# Sensors & Breakouts
include(micropython-common-breakouts)
include(pcf85063a/micropython)
# Utility
include(adcfft/micropython)
# LEDs & Matrices
include(plasma/micropython)
include(hub75/micropython)
# Packs
include(pico_unicorn/micropython)
include(pico_scroll/micropython)
include(pico_rgb_keypad/micropython)
# Servos & Motors
include(pwm/micropython)
include(servo/micropython)
include(encoder/micropython)
include(motor/micropython)
# include(micropython-common)
include(modules_py/modules_py)
include(micropython-common)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -4,4 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(micropython-common)

Wyświetl plik

@ -4,6 +4,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Essential
include(pimoroni_i2c/micropython)
include(pimoroni_bus/micropython)

Wyświetl plik

@ -32,11 +32,11 @@ void pimoroni_tuple_or_list(const mp_obj_t &object, mp_obj_t **items, size_t *le
}
uint8_t* pimoroni_motors_from_items(mp_obj_t *items, size_t length, int motor_count) {
uint8_t *motors = new uint8_t[length];
uint8_t *motors = m_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;
m_free(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 {
@ -636,7 +636,7 @@ mp_obj_t MotorCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t
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];
pins = m_new(pin_pair, 1);
pair_count = 1;
int pos = mp_obj_get_int(items[0]);
@ -656,7 +656,7 @@ mp_obj_t MotorCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t
}
else {
// Create and populate a local array of pins
pins = new pin_pair[pair_count];
pins = m_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)) {

Wyświetl plik

@ -5,21 +5,20 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Module Functions *****/
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_init_obj, picokeypad_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_width_obj, picokeypad_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_height_obj, picokeypad_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_num_pads_obj, picokeypad_get_num_pads);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_update_obj, picokeypad_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_set_brightness_obj, picokeypad_set_brightness);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_xy_obj, 5, 5, picokeypad_illuminate_xy);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_obj, 4, 4, picokeypad_illuminate);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_clear_obj, picokeypad_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picokeypad_get_button_states_obj, picokeypad_get_button_states);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad___del___obj, picokeypad___del__);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_width_obj, picokeypad_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_height_obj, picokeypad_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_num_pads_obj, picokeypad_get_num_pads);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_update_obj, picokeypad_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picokeypad_set_brightness_obj, picokeypad_set_brightness);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_xy_obj, 6, 6, picokeypad_illuminate_xy);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picokeypad_illuminate_obj, 5, 5, picokeypad_illuminate);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_clear_obj, picokeypad_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picokeypad_get_button_states_obj, picokeypad_get_button_states);
/***** Globals Table *****/
STATIC const mp_map_elem_t picokeypad_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picokeypad) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picokeypad_init_obj) },
/* Class Methods */
STATIC const mp_rom_map_elem_t picokeypad_locals[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picokeypad___del___obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picokeypad_get_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picokeypad_get_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_num_pads), MP_ROM_PTR(&picokeypad_get_num_pads_obj) },
@ -30,9 +29,34 @@ STATIC const mp_map_elem_t picokeypad_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picokeypad_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_button_states), MP_ROM_PTR(&picokeypad_get_button_states_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_globals, picokeypad_globals_table);
STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_locals, picokeypad_locals);
#ifdef MP_DEFINE_CONST_OBJ_TYPE
MP_DEFINE_CONST_OBJ_TYPE(
PicoKeypad_type,
MP_QSTR_PicoKeypad,
MP_TYPE_FLAG_NONE,
make_new, picokeypad_make_new,
locals_dict, (mp_obj_dict_t*)&mp_module_picokeypad_locals
);
#else
const mp_obj_type_t PicoKeypad_type = {
{ &mp_type_type },
.name = MP_QSTR_PicoKeypad,
.make_new = picokeypad_make_new,
.locals_dict = (mp_obj_dict_t*)&mp_module_picokeypad_locals,
};
#endif
/* Module Globals */
STATIC const mp_map_elem_t picokeypad_globals[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picokeypad) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PicoKeypad), (mp_obj_t)&PicoKeypad_type },
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(4) },
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(4) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picokeypad_globals, picokeypad_globals);
/***** Module Definition *****/
const mp_obj_module_t picokeypad_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_picokeypad_globals,

Wyświetl plik

@ -2,134 +2,130 @@
#include "hardware/sync.h"
#include "pico/binary_info.h"
#include "micropython/modules/util.hpp"
#include "libraries/pico_rgb_keypad/pico_rgb_keypad.hpp"
using namespace pimoroni;
PicoRGBKeypad *keypad = nullptr;
extern "C" {
#include "pico_rgb_keypad.h"
#define NOT_INITIALISED_MSG "Cannot call this function, as picokeypad is not initialised. Call picokeypad.init() first."
typedef struct _PicoKeypad_obj_t {
mp_obj_base_t base;
PicoRGBKeypad* keypad;
} PicoKeypad_obj_t;
mp_obj_t picokeypad_init() {
if(keypad == nullptr) {
keypad = new PicoRGBKeypad();
keypad->init();
}
mp_obj_t picokeypad_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_PicoKeypad_obj_t *self = nullptr;
self = m_new_obj_with_finaliser(PicoKeypad_obj_t);
self->base.type = &PicoKeypad_type;
self->keypad = m_new_class(PicoRGBKeypad);
self->keypad->init();
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t picokeypad___del__(mp_obj_t self_in) {
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t);
m_del_class(PicoRGBKeypad, self->keypad);
return mp_const_none;
}
mp_obj_t picokeypad_get_width() {
mp_obj_t picokeypad_get_width(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoRGBKeypad::WIDTH);
}
mp_obj_t picokeypad_get_height() {
mp_obj_t picokeypad_get_height(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoRGBKeypad::HEIGHT);
}
mp_obj_t picokeypad_get_num_pads() {
mp_obj_t picokeypad_get_num_pads(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoRGBKeypad::NUM_PADS);
}
mp_obj_t picokeypad_update() {
if(keypad != nullptr)
keypad->update();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
mp_obj_t picokeypad_update(mp_obj_t self_in) {
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t);
self->keypad->update();
return mp_const_none;
}
mp_obj_t picokeypad_set_brightness(mp_obj_t brightness_obj) {
if(keypad != nullptr) {
float brightness = mp_obj_get_float(brightness_obj);
mp_obj_t picokeypad_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) {
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t);
if(brightness < 0 || brightness > 1.0f)
mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0");
else
keypad->set_brightness(brightness);
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
float brightness = mp_obj_get_float(brightness_obj);
if(brightness < 0 || brightness > 1.0f)
mp_raise_ValueError("brightness out of range. Expected 0.0 to 1.0");
self->keypad->set_brightness(brightness);
return mp_const_none;
}
mp_obj_t picokeypad_illuminate_xy(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's 5
(void)n_args; //Unused input parameter, we know it's self + 5
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoKeypad_obj_t);
if(keypad != nullptr) {
int x = mp_obj_get_int(args[0]);
int y = mp_obj_get_int(args[1]);
int r = mp_obj_get_int(args[2]);
int g = mp_obj_get_int(args[3]);
int b = mp_obj_get_int(args[4]);
int x = mp_obj_get_int(args[1]);
int y = mp_obj_get_int(args[2]);
int r = mp_obj_get_int(args[3]);
int g = mp_obj_get_int(args[4]);
int b = mp_obj_get_int(args[5]);
if(x < 0 || x >= PicoRGBKeypad::WIDTH || y < 0 || y >= PicoRGBKeypad::HEIGHT)
mp_raise_ValueError("x or y out of range.");
else {
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
keypad->illuminate(x, y, r, g, b);
}
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
if(x < 0 || x >= PicoRGBKeypad::WIDTH || y < 0 || y >= PicoRGBKeypad::HEIGHT)
mp_raise_ValueError("x or y out of range.");
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
self->keypad->illuminate(x, y, r, g, b);
return mp_const_none;
}
mp_obj_t picokeypad_illuminate(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's 5
(void)n_args; //Unused input parameter, we know it's self + 5
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoKeypad_obj_t);
if(keypad != nullptr) {
int i = mp_obj_get_int(args[0]);
int r = mp_obj_get_int(args[1]);
int g = mp_obj_get_int(args[2]);
int b = mp_obj_get_int(args[3]);
int i = mp_obj_get_int(args[1]);
int r = mp_obj_get_int(args[2]);
int g = mp_obj_get_int(args[3]);
int b = mp_obj_get_int(args[4]);
if(i < 0 || i >= PicoRGBKeypad::NUM_PADS)
mp_raise_ValueError("x or y out of range.");
else {
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
keypad->illuminate(i, r, g, b);
}
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
if(i < 0 || i >= PicoRGBKeypad::NUM_PADS)
mp_raise_ValueError("x or y out of range.");
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
self->keypad->illuminate(i, r, g, b);
return mp_const_none;
}
mp_obj_t picokeypad_clear() {
if(keypad != nullptr)
keypad->clear();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
mp_obj_t picokeypad_clear(mp_obj_t self_in) {
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t);
self->keypad->clear();
return mp_const_none;
}
mp_obj_t picokeypad_get_button_states() {
mp_obj_t picokeypad_get_button_states(mp_obj_t self_in) {
PicoKeypad_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoKeypad_obj_t);
uint16_t states = 0;
if(keypad != nullptr)
states = keypad->get_button_states();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
states = self->keypad->get_button_states();
return mp_obj_new_int(states);
}
}

Wyświetl plik

@ -1,14 +1,17 @@
// Include MicroPython API.
#include "py/runtime.h"
extern const mp_obj_type_t PicoKeypad_type;
// Declare the functions we'll make available in Python
extern mp_obj_t picokeypad_init();
extern mp_obj_t picokeypad_get_width();
extern mp_obj_t picokeypad_get_height();
extern mp_obj_t picokeypad_get_num_pads();
extern mp_obj_t picokeypad_update();
extern mp_obj_t picokeypad_set_brightness(mp_obj_t brightness_obj);
extern mp_obj_t picokeypad_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t picokeypad___del__(mp_obj_t self_in);
extern mp_obj_t picokeypad_get_width(mp_obj_t self_in);
extern mp_obj_t picokeypad_get_height(mp_obj_t self_in);
extern mp_obj_t picokeypad_get_num_pads(mp_obj_t self_in);
extern mp_obj_t picokeypad_update(mp_obj_t self_in);
extern mp_obj_t picokeypad_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj);
extern mp_obj_t picokeypad_illuminate_xy(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picokeypad_illuminate(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picokeypad_clear();
extern mp_obj_t picokeypad_get_button_states();
extern mp_obj_t picokeypad_clear(mp_obj_t self_in);
extern mp_obj_t picokeypad_get_button_states(mp_obj_t self_in);

Wyświetl plik

@ -5,28 +5,27 @@ Our Pico Scroll Pack offers a 17x7 white LED matrix for your Raspberry Pi Pico.
We've included helper functions to handle every aspect of drawing to the matrix and interfacing with the buttons. See the [function reference](#function-reference) for details.
- [Example Program](#example-program)
- [Function Reference](#function-reference)
- [init](#init)
- [get_width](#get_width)
- [get_height](#get_height)
- [set_pixel](#set_pixel)
- [set_pixels](#set_pixels)
- [show_text](#show_text)
- [scroll_text](#scroll_text)
- [show_bitmap_1d](#show_bitmap_1d)
- [Function reference](#function-reference)
- [get\_width](#get_width)
- [get\_height](#get_height)
- [set\_pixel](#set_pixel)
- [set\_pixels](#set_pixels)
- [show\_text](#show_text)
- [scroll\_text](#scroll_text)
- [show\_bitmap\_1d](#show_bitmap_1d)
- [update](#update)
- [clear](#clear)
- [is_pressed](#is_pressed)
- [is\_pressed](#is_pressed)
## Example Program
The following example sets up the matrix, sets each pixel to an increasing brightnesses level, and then clears the matrix only after button A is pressed.
```python
import picoscroll
from picoscroll import PicoScroll
# Initialise the board
picoscroll.init()
picoscroll = PicoScroll()
brightness = 0
@ -51,14 +50,6 @@ picoscroll.update()
## Function reference
### init
Sets up the Pico Scroll Pack. The `init` function must be called before any other functions as it configures the required pins on the Pico board.
```python
picoscroll.init()
```
### get_width
### get_height

Wyświetl plik

@ -15,40 +15,70 @@ enum buttons
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Module Functions *****/
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_init_obj, picoscroll_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_width_obj, picoscroll_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_get_height_obj, picoscroll_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_update_obj, picoscroll_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_set_pixel_obj, picoscroll_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_set_pixels_obj, picoscroll_set_pixels);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_show_text_obj, picoscroll_show_text);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_scroll_text_obj, picoscroll_scroll_text);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picoscroll_show_bitmap_1d_obj, picoscroll_show_bitmap_1d);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picoscroll_clear_obj, picoscroll_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_is_pressed_obj, picoscroll_is_pressed);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll___del___obj, picoscroll___del__);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_width_obj, picoscroll_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_get_height_obj, picoscroll_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_show_obj, picoscroll_show);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_set_pixel_obj, 4, 4, picoscroll_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_set_pixels_obj, picoscroll_set_pixels);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_text_obj, 4, 4, picoscroll_show_text);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_scroll_text_obj, 4, 4, picoscroll_scroll_text);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picoscroll_show_bitmap_1d_obj, 4, 4, picoscroll_show_bitmap_1d);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picoscroll_clear_obj, picoscroll_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_is_pressed_obj, picoscroll_is_pressed);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picoscroll_update_obj, picoscroll_update);
/***** Globals Table *****/
STATIC const mp_map_elem_t picoscroll_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picoscroll) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picoscroll_init_obj) },
/* Class Methods */
STATIC const mp_rom_map_elem_t picoscroll_locals[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picoscroll___del___obj) },
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoscroll_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&picoscroll_show_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picoscroll_get_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picoscroll_get_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picoscroll_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picoscroll_set_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pixels), MP_ROM_PTR(&picoscroll_set_pixels_obj) },
{ MP_ROM_QSTR(MP_QSTR_show_text), MP_ROM_PTR(&picoscroll_show_text_obj) },
{ MP_ROM_QSTR(MP_QSTR_scroll_text), MP_ROM_PTR(&picoscroll_scroll_text_obj) },
{ MP_ROM_QSTR(MP_QSTR_show_bitmap_1d), MP_ROM_PTR(&picoscroll_show_bitmap_1d_obj) },
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picoscroll_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoscroll_is_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picoscroll_is_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_globals, picoscroll_globals_table);
STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_locals, picoscroll_locals);
#ifdef MP_DEFINE_CONST_OBJ_TYPE
MP_DEFINE_CONST_OBJ_TYPE(
PicoScroll_type,
MP_QSTR_PicoScroll,
MP_TYPE_FLAG_NONE,
make_new, picoscroll_make_new,
locals_dict, (mp_obj_dict_t*)&mp_module_picoscroll_locals
);
#else
const mp_obj_type_t PicoScroll_type = {
{ &mp_type_type },
.name = MP_QSTR_PicoScroll,
.make_new = picoscroll_make_new,
.locals_dict = (mp_obj_dict_t*)&mp_module_picoscroll_locals,
};
#endif
/* Module Globals */
STATIC const mp_map_elem_t picoscroll_globals[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picoscroll) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PicoScroll), (mp_obj_t)&PicoScroll_type },
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(17) },
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(7) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picoscroll_globals, picoscroll_globals);
/***** Module Definition *****/
const mp_obj_module_t picoscroll_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_picoscroll_globals,

Wyświetl plik

@ -1,9 +1,12 @@
#include <cstdio>
#include "hardware/spi.h"
#include "hardware/sync.h"
#include "pico/binary_info.h"
#include "pico/stdlib.h"
#include "micropython/modules/util.hpp"
#include "libraries/pico_scroll/pico_scroll.hpp"
#include "libraries/pico_scroll/pico_scroll_font.hpp"
using namespace pimoroni;
@ -12,165 +15,219 @@ PicoScroll *scroll = nullptr;
extern "C" {
#include "pico_scroll.h"
#include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h"
#include "py/builtin.h"
#define NOT_INITIALISED_MSG "Cannot call this function, as picoscroll is not initialised. Call picoscroll.init() first."
#define BUFFER_TOO_SMALL_MSG "bytearray too small: len(image) < width * height."
#define INCORRECT_SIZE_MSG "Scroll height wrong: > 8 pixels."
mp_obj_t picoscroll_init() {
if(scroll == nullptr)
scroll = new PicoScroll();
scroll->init();
typedef struct _PicoScroll_obj_t {
mp_obj_base_t base;
PicoScroll* scroll;
} PicoScroll_obj_t;
// from picographics/picographics.cpp
// used to support accepting a PicoGraphics class
typedef struct _ModPicoGraphics_obj_t {
mp_obj_base_t base;
PicoGraphics *graphics;
DisplayDriver *display;
void *spritedata;
void *buffer;
_PimoroniI2C_obj_t *i2c;
} ModPicoGraphics_obj_t;
mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_PicoScroll_obj_t *self = nullptr;
self = m_new_obj_with_finaliser(PicoScroll_obj_t);
self->base.type = &PicoScroll_type;
self->scroll = m_new_class(PicoScroll);
self->scroll->init();
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t picoscroll___del__(mp_obj_t self_in) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
m_del_class(PicoScroll, self->scroll);
return mp_const_none;
}
mp_obj_t picoscroll_get_width() {
mp_obj_t picoscroll_get_width(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoScroll::WIDTH);
}
mp_obj_t picoscroll_get_height() {
mp_obj_t picoscroll_get_height(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoScroll::HEIGHT);
}
mp_obj_t picoscroll_update() {
if(scroll != nullptr)
scroll->update();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
mp_obj_t picoscroll_show(mp_obj_t self_in) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
self->scroll->update();
return mp_const_none;
}
mp_obj_t picoscroll_set_pixel(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj) {
if (scroll != nullptr) {
int x = mp_obj_get_int(x_obj);
int y = mp_obj_get_int(y_obj);
int val = mp_obj_get_int(v_obj);
mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's self + 3
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t);
if (x < 0 || x >= PicoScroll::WIDTH || y < 0 || y >= PicoScroll::HEIGHT)
mp_raise_ValueError("x or y out of range.");
else {
if (val < 0 || val > 255)
mp_raise_ValueError("val out of range. Expected 0 to 255");
else
scroll->set_pixel(x, y, val);
int x = mp_obj_get_int(args[1]);
int y = mp_obj_get_int(args[2]);
int val = mp_obj_get_int(args[3]);
if (x < 0 || x >= PicoScroll::WIDTH || y < 0 || y >= PicoScroll::HEIGHT)
mp_raise_ValueError("x or y out of range.");
if (val < 0 || val > 255)
mp_raise_ValueError("val out of range. Expected 0 to 255");
self->scroll->set_pixel(x, y, val);
return mp_const_none;
}
mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's self + 3
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t);
int brightness = mp_obj_get_int(args[2]);
int delay_ms = mp_obj_get_int(args[3]);
if(mp_obj_is_str_or_bytes(args[1])) {
GET_STR_DATA_LEN(args[1], str, str_len);
int draw_buffer_len = 6 * str_len;
char *draw_buffer = m_new(char, draw_buffer_len);
render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len);
for (int offset = -PicoScroll::WIDTH; offset < draw_buffer_len; offset++) {
self->scroll->clear();
self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset);
self->scroll->update();
MICROPY_EVENT_POLL_HOOK
sleep_ms(delay_ms);
}
} else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
m_free(draw_buffer);
mp_obj_t picoscroll_scroll_text(mp_obj_t text_obj, mp_obj_t brightness_obj,
mp_obj_t delay_ms_obj) {
if (scroll != nullptr) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(text_obj, &bufinfo, MP_BUFFER_READ);
int brightness = mp_obj_get_int(brightness_obj);
int delay_ms = mp_obj_get_int(delay_ms_obj);
scroll->scroll_text((const char *)bufinfo.buf, bufinfo.len, brightness, delay_ms);
} else {
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
self->scroll->clear();
self->scroll->update();
}
return mp_const_none;
}
mp_obj_t picoscroll_show_text(mp_obj_t text_obj, mp_obj_t brightness_obj,
mp_obj_t offset_obj) {
if (scroll != nullptr) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(text_obj, &bufinfo, MP_BUFFER_READ);
int brightness = mp_obj_get_int(brightness_obj);
int offset = mp_obj_get_int(offset_obj);
mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's self + 3
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t);
scroll->set_text((const char *)bufinfo.buf, bufinfo.len, brightness, offset);
} else {
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
int brightness = mp_obj_get_int(args[2]);
int offset = mp_obj_get_int(args[3]);
if(mp_obj_is_str_or_bytes(args[1])) {
GET_STR_DATA_LEN(args[1], str, str_len);
int draw_buffer_len = 6 * str_len;
char *draw_buffer = m_new(char, draw_buffer_len);
render_text((const char *)str, str_len, (unsigned char *)draw_buffer, draw_buffer_len);
self->scroll->set_bitmap_1d((const char *)draw_buffer, draw_buffer_len, brightness, offset);
m_free(draw_buffer);
}
return mp_const_none;
}
mp_obj_t picoscroll_set_pixels(mp_obj_t image_obj) {
if (scroll != nullptr) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(image_obj, &bufinfo, MP_BUFFER_RW);
mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
if (bufinfo.len < (PicoScroll::WIDTH * PicoScroll::HEIGHT)) {
mp_raise_msg(&mp_type_IndexError, BUFFER_TOO_SMALL_MSG);
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(image_obj, &bufinfo, MP_BUFFER_RW);
scroll->set_pixels((const char*)bufinfo.buf);
} else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return mp_const_none;
}
mp_obj_t picoscroll_show_bitmap_1d(mp_obj_t bitmap_obj, mp_obj_t brightness_obj,
mp_obj_t offset_obj) {
if (scroll != nullptr) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(bitmap_obj, &bufinfo, MP_BUFFER_RW);
int offset = mp_obj_get_int(offset_obj);
int brightness = mp_obj_get_int(brightness_obj);
int length = bufinfo.len;
// clear the scroll, so only need to write visible bytes
scroll->clear();
if ((offset < -PicoScroll::WIDTH) || (offset > length)) {
return mp_const_none;
}
scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset);
} else {
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
if (bufinfo.len < (PicoScroll::WIDTH * PicoScroll::HEIGHT)) {
mp_raise_msg(&mp_type_IndexError, BUFFER_TOO_SMALL_MSG);
}
self->scroll->set_pixels((const char*)bufinfo.buf);
return mp_const_none;
}
mp_obj_t picoscroll_clear() {
if (scroll != nullptr)
scroll->clear();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's self + 3
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(args[0], PicoScroll_obj_t);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_RW);
int offset = mp_obj_get_int(args[3]);
int brightness = mp_obj_get_int(args[2]);
int length = bufinfo.len;
// clear the scroll, so only need to write visible bytes
self->scroll->clear();
if ((offset < -PicoScroll::WIDTH) || (offset > length)) {
return mp_const_none;
}
self->scroll->set_bitmap_1d((const char *)bufinfo.buf, bufinfo.len, brightness, offset);
return mp_const_none;
}
mp_obj_t picoscroll_is_pressed(mp_obj_t button_obj) {
mp_obj_t picoscroll_clear(mp_obj_t self_in) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
self->scroll->clear();
return mp_const_none;
}
mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
bool buttonPressed = false;
if(scroll != nullptr) {
int buttonID = mp_obj_get_int(button_obj);
switch(buttonID) {
case 0:
buttonPressed = scroll->is_pressed(PicoScroll::A);
break;
case 1:
buttonPressed = scroll->is_pressed(PicoScroll::B);
break;
int buttonID = mp_obj_get_int(button_obj);
switch(buttonID) {
case 0:
buttonPressed = self->scroll->is_pressed(PicoScroll::A);
break;
case 2:
buttonPressed = scroll->is_pressed(PicoScroll::X);
break;
case 1:
buttonPressed = self->scroll->is_pressed(PicoScroll::B);
break;
case 3:
buttonPressed = scroll->is_pressed(PicoScroll::Y);
break;
case 2:
buttonPressed = self->scroll->is_pressed(PicoScroll::X);
break;
default:
mp_raise_ValueError("button not valid. Expected 0 to 3");
break;
}
case 3:
buttonPressed = self->scroll->is_pressed(PicoScroll::Y);
break;
default:
mp_raise_ValueError("button not valid. Expected 0 to 3");
break;
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return buttonPressed ? mp_const_true : mp_const_false;
}
mp_obj_t picoscroll_update(mp_obj_t self_in, mp_obj_t graphics_in) {
PicoScroll_obj_t *self = MP_OBJ_TO_PTR2(self_in, PicoScroll_obj_t);
ModPicoGraphics_obj_t *picographics = MP_OBJ_TO_PTR2(graphics_in, ModPicoGraphics_obj_t);
if(picographics->base.type == &ModPicoGraphics_type) {
self->scroll->update(picographics->graphics);
}
return mp_const_none;
}
}

Wyświetl plik

@ -1,15 +1,22 @@
// Include MicroPython API.
#include "py/runtime.h"
#include "py/objstr.h"
extern const mp_obj_type_t PicoScroll_type;
extern const mp_obj_type_t ModPicoGraphics_type;
// Declare the functions we'll make available in Python
extern mp_obj_t picoscroll_init();
extern mp_obj_t picoscroll_get_width();
extern mp_obj_t picoscroll_get_height();
extern mp_obj_t picoscroll_update();
extern mp_obj_t picoscroll_set_pixel(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj);
extern mp_obj_t picoscroll_set_pixels(mp_obj_t image_obj);
extern mp_obj_t picoscroll_show_text(mp_obj_t text_obj, mp_obj_t brightness, mp_obj_t offset);
extern mp_obj_t picoscroll_scroll_text(mp_obj_t text_obj, mp_obj_t brightness, mp_obj_t delay);
extern mp_obj_t picoscroll_show_bitmap_1d(mp_obj_t bitmap_obj, mp_obj_t brightness, mp_obj_t offset);
extern mp_obj_t picoscroll_clear();
extern mp_obj_t picoscroll_is_pressed(mp_obj_t button_obj);
extern mp_obj_t picoscroll_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t picoscroll___del__(mp_obj_t self_in);
extern mp_obj_t picoscroll_get_width(mp_obj_t self_in);
extern mp_obj_t picoscroll_get_height(mp_obj_t self_in);
extern mp_obj_t picoscroll_show(mp_obj_t self_in);
extern mp_obj_t picoscroll_set_pixel(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picoscroll_set_pixels(mp_obj_t self_in, mp_obj_t image_obj);
extern mp_obj_t picoscroll_show_text(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picoscroll_scroll_text(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picoscroll_show_bitmap_1d(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picoscroll_clear(mp_obj_t self_in);
extern mp_obj_t picoscroll_is_pressed(mp_obj_t self_in, mp_obj_t button_obj);
extern mp_obj_t picoscroll_update(mp_obj_t self_in, mp_obj_t graphics_in);

Wyświetl plik

@ -10,6 +10,7 @@ pico_generate_pio_header(usermod_pico_unicorn ${CMAKE_CURRENT_LIST_DIR}/../../..
target_include_directories(usermod_pico_unicorn INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/
)
target_compile_definitions(usermod_pico_unicorn INTERFACE

Wyświetl plik

@ -16,30 +16,55 @@ enum buttons
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Module Functions *****/
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_init_obj, picounicorn_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_width_obj, picounicorn_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_get_height_obj, picounicorn_get_height);
//STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_update_obj, picounicorn_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_obj, 5, 5, picounicorn_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(picounicorn_set_pixel_value_obj, picounicorn_set_pixel_value);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(picounicorn_clear_obj, picounicorn_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_is_pressed_obj, picounicorn_is_pressed);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn__del__obj, picounicorn__del__);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_obj, 6, 6, picounicorn_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picounicorn_set_pixel_value_obj, 4, 4, picounicorn_set_pixel_value);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_clear_obj, picounicorn_clear);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picounicorn_is_pressed_obj, picounicorn_is_pressed);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_width_obj, picounicorn_get_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(picounicorn_get_height_obj, picounicorn_get_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(picounicorn_update_obj, picounicorn_update);
/***** Globals Table *****/
STATIC const mp_rom_map_elem_t picounicorn_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picounicorn) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picounicorn_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picounicorn_get_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picounicorn_get_height_obj) },
//{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picounicorn_update_obj) },
STATIC const mp_rom_map_elem_t picounicorn_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&picounicorn__del__obj) },
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&picounicorn_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&picounicorn_set_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_pixel_value), MP_ROM_PTR(&picounicorn_set_pixel_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picounicorn_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picounicorn_is_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picounicorn_is_pressed_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&picounicorn_get_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&picounicorn_get_height_obj) },
};
STATIC MP_DEFINE_CONST_DICT(picounicorn_locals_dict, picounicorn_locals_dict_table);
#ifdef MP_DEFINE_CONST_OBJ_TYPE
MP_DEFINE_CONST_OBJ_TYPE(
picounicorn_type,
MP_QSTR_PicoUnicorn,
MP_TYPE_FLAG_NONE,
make_new, picounicorn_make_new,
locals_dict, (mp_obj_dict_t*)&picounicorn_locals_dict
);
#else
const mp_obj_type_t picounicorn_type = {
{ &mp_type_type },
.name = MP_QSTR_PicoUnicorn,
.make_new = picounicorn_make_new,
.locals_dict = (mp_obj_dict_t*)&picounicorn_locals_dict,
};
#endif
/***** Globals Table *****/
STATIC const mp_rom_map_elem_t picounicorn_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picounicorn) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PicoUnicorn), (mp_obj_t)&picounicorn_type },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_INT(BUTTON_A) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_INT(BUTTON_B) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_INT(BUTTON_X) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON_Y), MP_ROM_INT(BUTTON_Y) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(16) },
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(7) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_picounicorn_globals, picounicorn_globals_table);

Wyświetl plik

@ -2,127 +2,146 @@
#include "hardware/sync.h"
#include "pico/binary_info.h"
#include "micropython/modules/util.hpp"
#include "libraries/pico_unicorn/pico_unicorn.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
using namespace pimoroni;
PicoUnicorn *unicorn = nullptr;
extern "C" {
#include "pico_unicorn.h"
#include "micropython/modules/pimoroni_i2c/pimoroni_i2c.h"
#include "py/builtin.h"
#define NOT_INITIALISED_MSG "Cannot call this function, as picounicorn is not initialised. Call picounicorn.init() first."
typedef struct _picounicorn_obj_t {
mp_obj_base_t base;
PicoUnicorn *unicorn;
} picounicorn_obj_t;
mp_obj_t picounicorn_init() {
if(unicorn == nullptr)
unicorn = new PicoUnicorn();
unicorn->init();
// from picographics/picographics.cpp
// used to support accepting a PicoGraphics class
typedef struct _ModPicoGraphics_obj_t {
mp_obj_base_t base;
PicoGraphics *graphics;
DisplayDriver *display;
void *spritedata;
void *buffer;
_PimoroniI2C_obj_t *i2c;
} ModPicoGraphics_obj_t;
mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
picounicorn_obj_t *self = m_new_obj_with_finaliser(picounicorn_obj_t);
self->base.type = &picounicorn_type;
self->unicorn = m_new_class(PicoUnicorn);
return MP_OBJ_FROM_PTR(self);
}
mp_obj_t picounicorn__del__(mp_obj_t self_in) {
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t);
m_del_class(PicoUnicorn, self->unicorn);
return mp_const_none;
}
mp_obj_t picounicorn_get_width() {
mp_obj_t picounicorn_get_width(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoUnicorn::WIDTH);
}
mp_obj_t picounicorn_get_height() {
mp_obj_t picounicorn_get_height(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_int(PicoUnicorn::HEIGHT);
}
// mp_obj_t picounicorn_update() {
// unicorn.update();
// return mp_const_none;
// }
mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; //Unused input parameter, we know it's 5
(void)n_args; // Unused input parameter, we know it's 5
if(unicorn != nullptr) {
int x = mp_obj_get_int(args[0]);
int y = mp_obj_get_int(args[1]);
int r = mp_obj_get_int(args[2]);
int g = mp_obj_get_int(args[3]);
int b = mp_obj_get_int(args[4]);
enum { ARG_self, ARG_x, ARG_y, ARG_r, ARG_g, ARG_b };
if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT)
mp_raise_ValueError("x or y out of range.");
else
{
if(r < 0 || r > 255)
mp_raise_ValueError("r out of range. Expected 0 to 255");
else if(g < 0 || g > 255)
mp_raise_ValueError("g out of range. Expected 0 to 255");
else if(b < 0 || b > 255)
mp_raise_ValueError("b out of range. Expected 0 to 255");
else
unicorn->set_pixel(x, y, r, g, b);
}
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], picounicorn_obj_t);
int x = mp_obj_get_int(args[ARG_x]);
int y = mp_obj_get_int(args[ARG_y]);
int r = mp_obj_get_int(args[ARG_r]);
int g = mp_obj_get_int(args[ARG_g]);
int b = mp_obj_get_int(args[ARG_b]);
if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) {
mp_raise_ValueError("x or y out of range.");
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
if(r < 0 || r > 255) mp_raise_ValueError("r out of range. Expected 0 to 255");
if(g < 0 || g > 255) mp_raise_ValueError("g out of range. Expected 0 to 255");
if(b < 0 || b > 255) mp_raise_ValueError("b out of range. Expected 0 to 255");
self->unicorn->set_pixel(x, y, r, g, b);
return mp_const_none;
}
mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj) {
if(unicorn != nullptr) {
int x = mp_obj_get_int(x_obj);
int y = mp_obj_get_int(y_obj);
int val = mp_obj_get_int(v_obj);
mp_obj_t picounicorn_set_pixel_value(size_t n_args, const mp_obj_t *args) {
enum { ARG_self, ARG_x, ARG_y, ARG_v };
if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT)
mp_raise_ValueError("x or y out of range.");
else {
if(val < 0 || val > 255)
mp_raise_ValueError("val out of range. Expected 0 to 255");
else
unicorn->set_pixel(x, y, val);
}
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], picounicorn_obj_t);
int x = mp_obj_get_int(args[ARG_x]);
int y = mp_obj_get_int(args[ARG_y]);
int val = mp_obj_get_int(args[ARG_v]);
if(x < 0 || x >= PicoUnicorn::WIDTH || y < 0 || y >= PicoUnicorn::HEIGHT) {
mp_raise_ValueError("x or y out of range.");
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
if(val < 0 || val > 255) mp_raise_ValueError("val out of range. Expected 0 to 255");
self->unicorn->set_pixel(x, y, val);
return mp_const_none;
}
mp_obj_t picounicorn_clear() {
if(unicorn != nullptr)
unicorn->clear();
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
mp_obj_t picounicorn_clear(mp_obj_t self_in) {
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t);
self->unicorn->clear();
return mp_const_none;
}
mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj) {
mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj) {
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t);
bool buttonPressed = false;
if(unicorn != nullptr) {
int buttonID = mp_obj_get_int(button_obj);
switch(buttonID) {
case 0:
buttonPressed = unicorn->is_pressed(PicoUnicorn::A);
break;
int buttonID = mp_obj_get_int(button_obj);
case 1:
buttonPressed = unicorn->is_pressed(PicoUnicorn::B);
break;
switch(buttonID) {
case 0:
buttonPressed = self->unicorn->is_pressed(PicoUnicorn::A);
break;
case 2:
buttonPressed = unicorn->is_pressed(PicoUnicorn::X);
break;
case 1:
buttonPressed = self->unicorn->is_pressed(PicoUnicorn::B);
break;
case 3:
buttonPressed = unicorn->is_pressed(PicoUnicorn::Y);
break;
case 2:
buttonPressed = self->unicorn->is_pressed(PicoUnicorn::X);
break;
default:
mp_raise_ValueError("button not valid. Expected 0 to 3");
break;
}
case 3:
buttonPressed = self->unicorn->is_pressed(PicoUnicorn::Y);
break;
default:
mp_raise_ValueError("button not valid. Expected 0 to 3");
break;
}
else
mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG);
return buttonPressed ? mp_const_true : mp_const_false;
}
mp_obj_t picounicorn_update(mp_obj_t self_in, mp_obj_t graphics_in) {
picounicorn_obj_t *self = MP_OBJ_TO_PTR2(self_in, picounicorn_obj_t);
ModPicoGraphics_obj_t *picographics = MP_OBJ_TO_PTR2(graphics_in, ModPicoGraphics_obj_t);
if(picographics->base.type == &ModPicoGraphics_type) {
self->unicorn->update(picographics->graphics);
}
return mp_const_none;
}
}

Wyświetl plik

@ -1,13 +1,16 @@
// Include MicroPython API.
//#include "py/obj.h"
#include "py/runtime.h"
// Declare the functions we'll make available in Python
extern mp_obj_t picounicorn_init();
extern mp_obj_t picounicorn_get_width();
extern mp_obj_t picounicorn_get_height();
//extern mp_obj_t picounicorn_update();
extern const mp_obj_type_t picounicorn_type;
extern const mp_obj_type_t ModPicoGraphics_type;
extern mp_obj_t picounicorn_get_width(mp_obj_t self_in);
extern mp_obj_t picounicorn_get_height(mp_obj_t self_in);
extern mp_obj_t picounicorn__del__(mp_obj_t self_in);
extern mp_obj_t picounicorn_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t picounicorn_set_pixel(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picounicorn_set_pixel_value(mp_obj_t x_obj, mp_obj_t y_obj, mp_obj_t v_obj);
extern mp_obj_t picounicorn_clear();
extern mp_obj_t picounicorn_is_pressed(mp_obj_t button_obj);
extern mp_obj_t picounicorn_set_pixel_value(mp_uint_t n_args, const mp_obj_t *args);
extern mp_obj_t picounicorn_clear(mp_obj_t self_in);
extern mp_obj_t picounicorn_is_pressed(mp_obj_t self_in, mp_obj_t button_obj);
extern mp_obj_t picounicorn_update(mp_obj_t self_in, mp_obj_t graphics_in);

Wyświetl plik

@ -2,6 +2,7 @@
#include "hardware/sync.h"
#include "pico/binary_info.h"
#include "micropython/modules/util.hpp"
#include "libraries/pico_wireless/pico_wireless.hpp"
using namespace pimoroni;
@ -51,7 +52,7 @@ mp_obj_t mp_ip_to_obj(IPAddress ip) {
mp_obj_t picowireless_init() {
if(wireless == nullptr)
wireless = new PicoWireless();
wireless = m_tracked_alloc_class(PicoWireless);
wireless->init();
return mp_const_none;
}

Wyświetl plik

@ -152,6 +152,8 @@ STATIC const mp_map_elem_t picographics_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_256X64), MP_ROM_INT(DISPLAY_INTERSTATE75_256X64) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME_7), MP_ROM_INT(DISPLAY_INKY_FRAME_7) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_COSMIC_UNICORN), MP_ROM_INT(DISPLAY_COSMIC_UNICORN) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_UNICORN_PACK), MP_ROM_INT(DISPLAY_UNICORN_PACK) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_SCROLL_PACK), MP_ROM_INT(DISPLAY_SCROLL_PACK) },
{ MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) },
{ MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) },

Wyświetl plik

@ -23,10 +23,10 @@ extern "C" {
#include "py/reader.h"
#include "extmod/vfs.h"
std::string mp_obj_to_string_r(const mp_obj_t &obj) {
const std::string_view mp_obj_to_string_r(const mp_obj_t &obj) {
if(mp_obj_is_str_or_bytes(obj)) {
GET_STR_DATA_LEN(obj, str, str_len);
return (const char*)str;
return std::string_view((const char*)str, str_len);
}
mp_raise_TypeError("can't convert object to str implicitly");
}
@ -210,6 +210,20 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
case DISPLAY_UNICORN_PACK:
width = 16;
height = 7;
bus_type = BUS_PIO;
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
case DISPLAY_SCROLL_PACK:
width = 17;
height = 7;
bus_type = BUS_PIO;
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
default:
return false;
}
@ -331,17 +345,18 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
} else if (display == DISPLAY_INKY_PACK) {
self->display = m_new_class(UC8151, width, height, (Rotation)rotate, spi_bus);
} else if (display == DISPLAY_GALACTIC_UNICORN) {
self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate);
} else if (display == DISPLAY_GFX_PACK) {
self->display = m_new_class(ST7567, width, height, spi_bus);
} else if (display == DISPLAY_INTERSTATE75_32X32 || display == DISPLAY_INTERSTATE75_64X64 || display == DISPLAY_INTERSTATE75_64X32) {
self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate);
} else if (display == DISPLAY_COSMIC_UNICORN) {
} else if (display == DISPLAY_INTERSTATE75_32X32
|| display == DISPLAY_INTERSTATE75_64X64
|| display == DISPLAY_INTERSTATE75_64X32
|| display == DISPLAY_GALACTIC_UNICORN
|| display == DISPLAY_COSMIC_UNICORN
|| display == DISPLAY_UNICORN_PACK
|| display == DISPLAY_SCROLL_PACK) {
// Create a dummy display driver
self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate);
} else {
@ -935,7 +950,7 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t
GET_STR_DATA_LEN(text_obj, str, str_len);
std::string t((const char*)str);
const std::string_view t((const char*)str, str_len);
int x = args[ARG_x].u_int;
int y = args[ARG_y].u_int;
@ -969,7 +984,7 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m
GET_STR_DATA_LEN(text_obj, str, str_len);
std::string t((const char*)str);
const std::string_view t((const char*)str, str_len);
float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj);
int letter_spacing = args[ARG_spacing].u_int;

Wyświetl plik

@ -25,7 +25,9 @@ enum PicoGraphicsDisplay {
DISPLAY_INTERSTATE75_192X64,
DISPLAY_INTERSTATE75_256X64,
DISPLAY_INKY_FRAME_7,
DISPLAY_COSMIC_UNICORN
DISPLAY_COSMIC_UNICORN,
DISPLAY_UNICORN_PACK,
DISPLAY_SCROLL_PACK
};
enum PicoGraphicsPenType {

Wyświetl plik

@ -1289,11 +1289,11 @@ mp_obj_t ServoCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of pins
pins = new uint8_t[pin_count];
pins = m_new(uint8_t, pin_count);
for(size_t i = 0; i < pin_count; i++) {
int pin = mp_obj_get_int(items[i]);
if(pin < 0 || pin >= (int)NUM_BANK0_GPIOS) {
delete[] pins;
m_free(pins);
mp_raise_ValueError("a pin in the list or tuple is out of range. Expected 0 to 29");
}
else {
@ -1348,7 +1348,7 @@ mp_obj_t ServoCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// Cleanup the pins array
if(pins != nullptr)
delete[] pins;
m_free(pins);
if(!cluster->init()) {
m_del_class(ServoCluster, cluster);
@ -1449,11 +1449,11 @@ extern mp_obj_t ServoCluster_enable(size_t n_args, const mp_obj_t *pos_args, mp_
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -1461,7 +1461,7 @@ extern mp_obj_t ServoCluster_enable(size_t n_args, const mp_obj_t *pos_args, mp_
}
}
self->cluster->enable(servos, length, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -1533,11 +1533,11 @@ extern mp_obj_t ServoCluster_disable(size_t n_args, const mp_obj_t *pos_args, mp
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -1545,7 +1545,7 @@ extern mp_obj_t ServoCluster_disable(size_t n_args, const mp_obj_t *pos_args, mp
}
}
self->cluster->disable(servos, length, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -1668,11 +1668,11 @@ extern mp_obj_t ServoCluster_pulse(size_t n_args, const mp_obj_t *pos_args, mp_m
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -1681,7 +1681,7 @@ extern mp_obj_t ServoCluster_pulse(size_t n_args, const mp_obj_t *pos_args, mp_m
}
float pulse = mp_obj_get_float(args[ARG_pulse].u_obj);
self->cluster->pulse(servos, length, pulse, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -1786,11 +1786,11 @@ extern mp_obj_t ServoCluster_value(size_t n_args, const mp_obj_t *pos_args, mp_m
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -1799,7 +1799,7 @@ extern mp_obj_t ServoCluster_value(size_t n_args, const mp_obj_t *pos_args, mp_m
}
float value = mp_obj_get_float(args[ARG_value].u_obj);
self->cluster->value(servos, length, value, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -1904,11 +1904,11 @@ extern mp_obj_t ServoCluster_phase(size_t n_args, const mp_obj_t *pos_args, mp_m
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -1917,7 +1917,7 @@ extern mp_obj_t ServoCluster_phase(size_t n_args, const mp_obj_t *pos_args, mp_m
}
float phase = mp_obj_get_float(args[ARG_phase].u_obj);
self->cluster->phase(servos, length, phase, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2108,11 +2108,11 @@ extern mp_obj_t ServoCluster_to_min(size_t n_args, const mp_obj_t *pos_args, mp_
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2120,7 +2120,7 @@ extern mp_obj_t ServoCluster_to_min(size_t n_args, const mp_obj_t *pos_args, mp_
}
}
self->cluster->to_min(servos, length, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2196,11 +2196,11 @@ extern mp_obj_t ServoCluster_to_mid(size_t n_args, const mp_obj_t *pos_args, mp_
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2208,7 +2208,7 @@ extern mp_obj_t ServoCluster_to_mid(size_t n_args, const mp_obj_t *pos_args, mp_
}
}
self->cluster->to_mid(servos, length, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2284,11 +2284,11 @@ extern mp_obj_t ServoCluster_to_max(size_t n_args, const mp_obj_t *pos_args, mp_
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2296,7 +2296,7 @@ extern mp_obj_t ServoCluster_to_max(size_t n_args, const mp_obj_t *pos_args, mp_
}
}
self->cluster->to_max(servos, length, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2376,11 +2376,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2389,7 +2389,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
}
float in = mp_obj_get_float(args[ARG_in].u_obj);
self->cluster->to_percent(servos, length, in, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2448,11 +2448,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2463,7 +2463,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
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(servos, length, in, in_min, in_max, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}
@ -2526,11 +2526,11 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
mp_raise_TypeError("list or tuple must contain at least one integer");
else {
// Create and populate a local array of servo indices
uint8_t *servos = new uint8_t[length];
uint8_t *servos = m_new(uint8_t, length);
for(size_t i = 0; i < length; i++) {
int servo = mp_obj_get_int(items[i]);
if(servo < 0 || servo >= servo_count) {
delete[] servos;
m_free(servos);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("a servo in the list or tuple is out of range. Expected 0 to %d"), servo_count - 1);
}
else {
@ -2543,7 +2543,7 @@ extern mp_obj_t ServoCluster_to_percent(size_t n_args, const mp_obj_t *pos_args,
float value_min = mp_obj_get_float(args[ARG_value_min].u_obj);
float value_max = mp_obj_get_float(args[ARG_value_max].u_obj);
self->cluster->to_percent(servos, length, in, in_min, in_max, value_min, value_max, args[ARG_load].u_bool);
delete[] servos;
m_free(servos);
}
}
}

Wyświetl plik

@ -13,4 +13,7 @@
#define m_new_class(cls, ...) new(m_new(cls, 1)) cls(__VA_ARGS__)
#define m_del_class(cls, ptr) ptr->~cls();m_del(cls, ptr, 1)
#define m_del_class(cls, ptr) ptr->~cls();m_del(cls, ptr, 1)
#define m_tracked_alloc_class(cls, ...) new(m_tracked_calloc(1, sizeof(cls))) cls(__VA_ARGS__)
#define m_tracked_free_class(cls, ptr) ptr->~cls();m_tracked_free(ptr)