Porównaj commity

...

32 Commity

Autor SHA1 Wiadomość Data
Philip Howard 1a0a83ebd1
Merge 34b8b4d81f into be3e7ba83a 2024-11-26 11:55:57 +00:00
Phil Howard 34b8b4d81f PicoVector: MPY bindings for line and arc. 2024-11-26 11:55:32 +00:00
Phil Howard a2c48a8f44 PicoVector: Tweak for C++ compatibility. 2024-11-26 11:12:24 +00:00
Mike Bell c1e0631102 PicoVector: Avoid clipping bottom right AA edges. 2024-11-26 10:43:11 +00:00
Jonathan Williamson c91b498505 PicoVector: Add star and line primitives. 2024-11-26 10:43:08 +00:00
Philip Howard be3e7ba83a
Merge pull request #1030 from pimoroni/patch-pcf85063a-rp2350
pcf85063a: RP2350 Fixes
2024-11-26 10:05:15 +00:00
Phil Howard b6f657f9fc pcf85063a: Set PICO_INCLUDE_RTC_DATETIME.
And remove set_datetime and get_datetime gracefully when it's not set.

This is a temporary work-around for RP2350 lacking an RTC and not
requiring the datetime_t type. These functions should be re-implemented
in terms of C standards.
2024-11-25 13:19:44 +00:00
Phil Howard c08f496ecf pcf85063a: Drop hardware_rtc.
With datetime_t moved to types there is no need to include this as a dependency.
2024-11-25 12:33:54 +00:00
Phil Howard ad5120a8d2 PicoGraphics: Implement RGB888 alpha blending. 2024-11-21 22:28:10 +00:00
Mike Bell 18d3ed3940 Hub75: Reformat loop for performance.
~3.09ms to ~2.87ms per frame without overclock.
2024-11-21 22:08:10 +00:00
Phil Howard acf6e517f6 Hub75: Performance improvements and stacked mode.
Inline and simplify the pixel flip for a 13.2ms -> 3.8ms speedup at 128x128 on RP2350 stock.

Drop RGB565 mode.

Add the ability to stack some panels, eg: 2x128x64 in a 128x127 configuration.
2024-11-21 20:59:39 +00:00
Phil Howard 896353af11 PicoVector: Avoid MicroPython GC.
Since we're not using tracked allocation, any memory we don't explicitly
hold a reference to will be assumed unused by MicroPython's GC.

Pass up the pp_nodes and pp_node_counts points (hackily) to fix this.
2024-11-21 12:08:48 +00:00
Phil Howard b184475bc0 PicoVector: Remove * 4 from pp_nodes lookup. 2024-11-21 11:14:07 +00:00
Phil Howard d8c6883fc0 PicoGraphics/Hub75: Add support for 128x128. 2024-11-20 12:46:05 +00:00
Phil Howard adfa429d47 PicoVector: Update example with text bounds. 2024-11-20 11:21:27 +00:00
Phil Howard d44f00886b PicoGraphics: Don't force Presto to RGB565. 2024-11-20 10:46:06 +00:00
Mike Bell 5f08e113bd PicoGraphics: Presto full res option. 2024-11-19 11:01:28 +00:00
Mike Bell 0807dc6810 PicoVector: Apply overall transform to text rendering. 2024-11-19 11:01:20 +00:00
Mike Bell 8471580c71 PicoVector: Add optional text max width and max height. 2024-11-19 11:01:12 +00:00
Phil Howard 6b0195a00b PicoVector: Revert the tile buffer to be fixed.
Ensure that MicroPython doesn't ever place the tile buffer into PSRAM
and trash performance.
2024-11-18 14:00:46 +00:00
Phil Howard ab81c5df56 PicoVector: Runtime buffer allocation. 2024-11-18 14:00:37 +00:00
Philip Howard 1495805d2b
Merge pull request #947 from pimoroni/test/network-ppp
PPP-enabled Pico build.
2024-10-31 12:19:50 +00:00
Philip Howard fd4b2922e4
Merge pull request #957 from pimoroni/plasma-stick-brightness
add brightness control to default Plasma Stick W example
2024-10-31 12:13:53 +00:00
Philip Howard b8f4bd3f67
Merge pull request #966 from pimoroni/examples-fix-adc
Examples: Update ADC()
2024-10-31 12:13:24 +00:00
Phil Howard ef936ba907 RPI_PICO_PPP: Lint lte module. 2024-10-31 11:19:22 +00:00
Phil Howard a1be7a6327 RPI_PICO_PPP: Add lte module. 2024-10-31 11:19:22 +00:00
Phil Howard a05a225262 Wakeup: Move wakeup pin assert and latch out of patches. 2024-10-31 11:19:22 +00:00
Phil Howard 6cfcd80037 PPP: This old chestnut. 2024-10-31 11:19:22 +00:00
Phil Howard 81455d129d RPI_PICO_PPP: Tweak flash/fw alloc to fit PPP support. 2024-10-31 11:19:22 +00:00
Phil Howard d24c2225ca CI: PPP-enabled Pico build. 2024-10-31 11:19:11 +00:00
Hel Gibbons b5d496bc90 Examples: Update ADC() 2024-07-02 12:45:29 +01:00
Hel Gibbons 6264b96efe add brightness control to default example 2024-01-25 16:39:06 +00:00
38 zmienionych plików z 781 dodań i 254 usunięć

Wyświetl plik

@ -22,6 +22,8 @@ jobs:
board: RPI_PICO
- name: pico_usb
board: RPI_PICO_USB
- name: pico_ppp
board: RPI_PICO_PPP
- name: picow
board: RPI_PICO_W
- name: tiny2040_8mb

Wyświetl plik

@ -37,10 +37,48 @@ Hub75::Hub75(uint width, uint height, Pixel *buffer, PanelType panel_type, bool
}
if (brightness == 0) {
#if PICO_RP2350
brightness = 6;
#else
if (width >= 64) brightness = 6;
if (width >= 96) brightness = 3;
if (width >= 128) brightness = 2;
if (width >= 160) brightness = 1;
#endif
}
switch (color_order) {
case COLOR_ORDER::RGB:
r_shift = 0;
g_shift = 10;
b_shift = 20;
break;
case COLOR_ORDER::RBG:
r_shift = 0;
g_shift = 20;
b_shift = 10;
break;
case COLOR_ORDER::GRB:
r_shift = 20;
g_shift = 0;
b_shift = 10;
break;
case COLOR_ORDER::GBR:
r_shift = 10;
g_shift = 20;
b_shift = 0;
break;
case COLOR_ORDER::BRG:
r_shift = 10;
g_shift = 00;
b_shift = 20;
break;
case COLOR_ORDER::BGR:
r_shift = 20;
g_shift = 10;
b_shift = 0;
break;
}
}
@ -58,26 +96,16 @@ void Hub75::set_color(uint x, uint y, Pixel c) {
}
void Hub75::set_pixel(uint x, uint y, uint8_t r, uint8_t g, uint8_t b) {
switch(color_order) {
case COLOR_ORDER::RGB:
set_color(x, y, Pixel(r, g, b));
break;
case COLOR_ORDER::RBG:
set_color(x, y, Pixel(r, b, g));
break;
case COLOR_ORDER::GRB:
set_color(x, y, Pixel(g, r, b));
break;
case COLOR_ORDER::GBR:
set_color(x, y, Pixel(g, b, r));
break;
case COLOR_ORDER::BRG:
set_color(x, y, Pixel(b, r, g));
break;
case COLOR_ORDER::BGR:
set_color(x, y, Pixel(b, g, r));
break;
int offset = 0;
if(x >= width || y >= height) return;
if(y >= height / 2) {
y -= height / 2;
offset = (y * width + x) * 2;
offset += 1;
} else {
offset = (y * width + x) * 2;
}
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
}
void Hub75::FM6126A_write_register(uint16_t value, uint8_t position) {
@ -249,28 +277,88 @@ void Hub75::dma_complete() {
void Hub75::update(PicoGraphics *graphics) {
if(graphics->pen_type == PicoGraphics::PEN_RGB888) {
uint32_t *p = (uint32_t *)graphics->frame_buffer;
for(uint y = 0; y < height; y++) {
for(uint 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;
set_pixel(x, y, r, g, b);
p++;
uint8_t *p = (uint8_t *)graphics->frame_buffer;
if(graphics->bounds.w == int32_t(width / 2) && graphics->bounds.h == int32_t(height * 2)) {
for(int y = 0; y < graphics->bounds.h; y++) {
int offsety = 0;
int sy = y;
int basex = 0;
// Assuming our canvas is 128x128 and our display is 256x64,
// consisting of 2x128x64 panels, remap the bottom half
// of the canvas to the right-half of the display,
// This gives us an optional square arrangement.
if (sy >= int(height)) {
sy -= height;
basex = width / 2;
} else {
// Awkward hack to *TEMPORARILY* rotate the top panel
sy = height - 1 - sy;
basex = (width / 2) - 1;
}
// Interlace the top and bottom halves of the panel.
// Since these are scanned out simultaneously to two chains
// of shift registers we need each pair of rows
// (N and N + height / 2) to be adjacent in the buffer.
offsety = width * 2;
if(sy >= int(height / 2)) {
sy -= height / 2;
offsety *= sy;
offsety += 1;
} else {
offsety *= sy;
}
for(int x = 0; x < graphics->bounds.w; x++) {
int sx = x;
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;
// Assumes width / 2 is even.
if (basex & 1) {
sx = basex - sx;
} else {
sx += basex;
}
int offset = offsety + sx * 2;
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
// Skip the empty byte in out 32-bit aligned 24-bit colour.
p++;
}
}
}
}
else if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
uint16_t *p = (uint16_t *)graphics->frame_buffer;
for(uint y = 0; y < height; y++) {
for(uint 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;
set_pixel(x, y, r, g, b);
p++;
} else {
for(uint y = 0; y < height; y++) {
for(uint x = 0; x < width; x++) {
int offset = 0;
int sy = y;
int sx = x;
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;
// Interlace the top and bottom halves of the panel.
// Since these are scanned out simultaneously to two chains
// of shift registers we need each pair of rows
// (N and N + height / 2) to be adjacent in the buffer.
offset = width * 2;
if(sy >= int(height / 2)) {
sy -= height / 2;
offset *= sy;
offset += 1;
} else {
offset *= sy;
}
offset += sx * 2;
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
// Skip the empty byte in out 32-bit aligned 24-bit colour.
p++;
}
}
}
}

Wyświetl plik

@ -65,6 +65,9 @@ class Hub75 {
};
uint width;
uint height;
uint r_shift = 0;
uint g_shift = 10;
uint b_shift = 20;
Pixel *back_buffer;
bool managed_buffer = false;
PanelType panel_type;

Wyświetl plik

@ -1,10 +1,14 @@
set(DRIVER_NAME pcf85063a)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c hardware_rtc pimoroni_i2c)
set(DRIVER_NAME pcf85063a)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Include datetime_t for cross-compatibility with RP2350 (no RTC) boards
# TODO: We should migrate away from using this non-standard type
target_compile_definitions(${DRIVER_NAME} INTERFACE PICO_INCLUDE_RTC_DATETIME=1)
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pico_util hardware_i2c pimoroni_i2c)

Wyświetl plik

@ -53,6 +53,8 @@ namespace pimoroni {
return interrupt;
}
#if PICO_INCLUDE_RTC_DATETIME
datetime_t PCF85063A::get_datetime() {
uint8_t result[7] = {0};
@ -85,6 +87,8 @@ namespace pimoroni {
i2c->write_bytes(address, Registers::SECONDS, data, 7);
}
#endif
void PCF85063A::set_alarm(int second, int minute, int hour, int day) {
uint8_t alarm[5] = {
uint8_t(second != PARAM_UNUSED ? bcd_encode(second) : 0x80),

Wyświetl plik

@ -108,10 +108,12 @@ namespace pimoroni {
int get_scl() const;
int get_int() const;
#if PICO_INCLUDE_RTC_DATETIME
// Set and get the date and time
// Uses datetime_t from pico sdk (hardware/rtc) for compatibility
datetime_t get_datetime();
void set_datetime(datetime_t *t);
#endif
// Alarm manipulation methods
void set_alarm(int second = PARAM_UNUSED, int minute = PARAM_UNUSED,

Wyświetl plik

@ -51,7 +51,7 @@ int main() {
pp_mat3_translate(&pos, 50, 50);
pp_mat3_rotate(&pos, a);
vector.draw(poly);
vector.text("Hello World", &pos);
vector.text("Hello World", 320, 240, &pos);
// update screen
st7789.update(&graphics);

Wyświetl plik

@ -38,19 +38,35 @@ namespace pimoroni {
}
bool PicoGraphics_PenRGB888::render_tile(const Tile *tile) {
for(int y = 0; y < tile->h; y++) {
uint8_t *palpha = &tile->data[(y * tile->stride)];
uint32_t *pdest = &((uint32_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
uint8_t *p_alpha = &tile->data[(y * tile->stride)];
uint32_t *p_dest = &((uint32_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
for(int x = 0; x < tile->w; x++) {
uint8_t alpha = *palpha;
uint16_t dest = *p_dest;
uint8_t alpha = *p_alpha;
// TODO: Alpha blending
if(alpha == 0) {
if(alpha == 255) {
*p_dest = color;
}else if(alpha == 0) {
} else {
*pdest = color;
// blend tha pixel
uint32_t sr = (color >> 16) & 0xff;
uint32_t sg = (color >> 8) & 0xff;
uint32_t sb = (color >> 0) & 0xff;
uint32_t dr = (dest >> 16) & 0xff;
uint32_t dg = (dest >> 8) & 0xff;
uint32_t db = (dest >> 0) & 0xff;
uint8_t r = ((sr * alpha) + (dr * (255 - alpha))) >> 8;
uint8_t g = ((sg * alpha) + (dg * (255 - alpha))) >> 8;
uint8_t b = ((sb * alpha) + (db * (255 - alpha))) >> 8;
*p_dest = (r << 16) | (g << 8) | b;
}
pdest++;
palpha++;
p_dest++;
p_alpha++;
}
}

Wyświetl plik

@ -31,6 +31,7 @@
#include <math.h>
#include <stdbool.h>
#include <wchar.h>
#include <float.h>
#ifdef AF_MALLOC
#ifndef PP_MALLOC
@ -104,8 +105,8 @@ typedef struct {
bool af_load_font_file(AF_FILE file, af_face_t *face);
void af_render_character(af_face_t *face, const char codepoint, af_text_metrics_t *tm);
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm);
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm);
#ifdef AF_USE_PRETTY_POLY
#endif
@ -240,20 +241,30 @@ void af_render_character(af_face_t *face, const char c, af_text_metrics_t *tm) {
af_render_glyph(glyph, tm);
}
int get_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
int line_width = 0;
char *end = (char *)text + tlen;
float get_line_width(af_face_t *face, const char *text, size_t *tlen, float max_line_width, af_text_metrics_t *tm) {
float line_width = 0;
const char *start = text;
const char *end = text + *tlen;
const char *last_space = nullptr;
for(char c = *text; text < end; text++, c = *text) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {
continue;
}
float char_width;
if(c == L' ') {
line_width += (glyph->advance * tm->word_spacing) / 100.0f;
char_width = (glyph->advance * tm->word_spacing) / 100.0f;
last_space = text;
} else {
line_width += (glyph->advance * tm->letter_spacing) / 100.0f;
char_width = (glyph->advance * tm->letter_spacing) / 100.0f;
}
if (max_line_width > 0 && line_width + char_width > max_line_width && last_space) {
*tlen = last_space - start;
break;
}
line_width += char_width;
}
return line_width;
}
@ -270,14 +281,14 @@ size_t line_length(const char *text, const char *end) {
return line_ending - text;
}
int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
int max_width = 0;
float get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
float max_width = 0;
char *line = (char *)text;
char *tend = line + tlen;
size_t line_len = line_length(line, tend);
while(line_len) {
int width = get_line_width(face, line, line_len, tm);
float width = get_line_width(face, line, &line_len, 0, tm);
max_width = max_width < width ? width : max_width;
line += line_len + 1;
line_len = line_length(line, tend);
@ -286,7 +297,7 @@ int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_m
return max_width;
}
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm) {
char *line = (char *)text;
char *tend = line + tlen;
size_t line_len = 0;
@ -304,15 +315,23 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
caret.y = 0;
// find maximum line length
int max_line_width = get_max_line_width(face, text, tlen, tm);
if (max_line_width == 0.f) {
max_line_width = get_max_line_width(face, text, tlen, tm);
} else {
max_line_width /= scale;
}
if (max_height == 0.f) {
max_height = FLT_MAX;
} else {
max_height /= scale;
}
line_len = line_length(line, tend);
while(line_len) {
while(line_len && caret.y + line_height <= max_height) {
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
char *end = line + line_len;
int line_width = get_line_width(face, line, line_len, tm);
for(char c = *line; line < end; line++, c = *line) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {
@ -331,7 +350,9 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
pp_mat3_translate(&caret_transform, (max_line_width - line_width), 0);
}
pp_transform(&caret_transform);
pp_mat3_t final_transform = *old;
pp_mat3_mul(&final_transform, &caret_transform);
pp_transform(&final_transform);
af_render_glyph(glyph, tm);
@ -356,10 +377,10 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
}
void _af_render(af_face_t *face, const char *text, af_text_metrics_t *tm) {
af_render(face, text, strlen(text), tm);
af_render(face, text, strlen(text), 0, 0, tm);
}
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm) {
pp_rect_t result;
bool first = true;
char *line = (char *)text;
@ -377,15 +398,14 @@ pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_met
caret.y = 0;
// find maximum line length
int max_line_width = get_max_line_width(face, text, tlen, tm);
if (max_line_width == 0.f) max_line_width = get_max_line_width(face, text, tlen, tm);
line_len = line_length(line, tend);
while(line_len) {
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
char *end = line + line_len;
int line_width = get_line_width(face, line, line_len, tm);
for(char c = *line; line < end; line++, c = *line) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {

Wyświetl plik

@ -60,93 +60,13 @@ namespace pimoroni {
}
}
pp_point_t PicoVector::text(std::string_view text, pp_mat3_t *t) {
pp_point_t PicoVector::text(std::string_view text, int max_width, int max_height, pp_mat3_t *t) {
pp_point_t caret = {0, 0};
text_metrics.transform = t;
af_render(text_metrics.face, text.data(), text.size(), &text_metrics);
af_render(text_metrics.face, text.data(), text.size(), max_width, max_height, &text_metrics);
return caret;
/*
// Align text from the bottom left
caret.y += (PP_COORD_TYPE)text_metrics.line_height;
caret = pp_point_transform(&caret, t);
caret.x += offset.x;
caret.y += offset.y;
pp_point_t space;
pp_point_t carriage_return = {0, -(PP_COORD_TYPE)text_metrics.line_height};
char spc = ' ';
space.x = af_measure(text_metrics.face, &spc, &text_metrics).w;
if (space.x == 0) {
space.x = text_metrics.word_spacing;
}
space = pp_point_transform(&space, t);
carriage_return = pp_point_transform(&carriage_return, t);
pp_point_t initial_carriage_return = carriage_return;
size_t i = 0;
while(i < text.length()) {
size_t next_space = text.find(' ', i + 1);
if(next_space == std::string::npos) {
next_space = text.length();
}
size_t next_linebreak = text.find('\n', i + 1);
if(next_linebreak == std::string::npos) {
next_linebreak = text.length();
}
size_t next_break = std::min(next_space, next_linebreak);
uint16_t word_width = 0;
for(size_t j = i; j < next_break; j++) {
word_width += af_measure(text_metrics.face, &text[j], &text_metrics).w;
word_width += text_metrics.letter_spacing;
}
if(caret.x != 0 && caret.x + word_width > graphics->clip.w) {
caret = pp_point_sub(&caret, &carriage_return);
carriage_return = initial_carriage_return;
}
for(size_t j = i; j < std::min(next_break + 1, text.length()); j++) {
if (text[j] == '\n') { // Linebreak
caret = pp_point_sub(&caret, &carriage_return);
carriage_return = initial_carriage_return;
} else if (text[j] == ' ') { // Space
caret = pp_point_add(&caret, &space);
carriage_return = pp_point_add(&carriage_return, &space);
} else {
// apply the caret offset...
pp_mat3_t pos = pp_mat3_identity();
pp_mat3_mul(&pos, t);
pp_mat3_translate(&pos, caret.x, caret.y);
text_metrics.transform = &pos;
af_render_character(text_metrics.face, text[j], &text_metrics);
}
pp_point_t advance = {
(PP_COORD_TYPE)af_measure(text_metrics.face, &text[j], &text_metrics).w + text_metrics.letter_spacing,
(PP_COORD_TYPE)0
};
advance = pp_point_transform(&advance, t);
caret = pp_point_add(&caret, &advance);
carriage_return = pp_point_add(&carriage_return, &advance);
}
i = next_break + 1;
}
return {caret.x, caret.y};
*/
}
}

Wyświetl plik

@ -31,12 +31,22 @@ namespace pimoroni {
class PicoVector {
private:
af_text_metrics_t text_metrics;
// Hold copies of pretty-poly's pointers
// so MicroPython does not garbage collect them!
void *_pp_nodes;
void *_pp_node_counts;
public:
static PicoGraphics *graphics;
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
PicoVector(PicoGraphics *graphics) {
PicoVector::graphics = graphics;
// TODO: Make these configurable?
// Tile buffer size, Max nodes per scanline
pp_init(16);
_pp_nodes = pp_nodes;
_pp_node_counts = pp_node_counts;
pp_tile_callback(PicoVector::tile_callback);
set_antialiasing(graphics->supports_alpha_blend() ? PP_AA_X4 : PP_AA_NONE);
@ -48,11 +58,15 @@ namespace pimoroni {
text_metrics.letter_spacing = 95;
text_metrics.word_spacing = 200;
text_metrics.size = 48;
// Shoud be set before rendering chars
// Should be set before rendering chars
//text_metrics.transform = (pp_mat3_t *)af_malloc(sizeof(pp_mat3_t));
//*text_metrics.transform = pp_mat3_identity();
}
~PicoVector() {
pp_deinit();
}
static void tile_callback(const pp_tile_t *tile) {
// TODO: we're using a cast here to avoid a hard dependency link between
// PicoGraphics and PicoVector. These types might subtly mismatch, though...
@ -85,7 +99,7 @@ namespace pimoroni {
pp_rect_t measure_text(std::string_view text, pp_mat3_t *t) {
text_metrics.transform = t;
return af_measure(text_metrics.face, text.data(), text.size(), &text_metrics);
return af_measure(text_metrics.face, text.data(), text.size(), 0, &text_metrics);
}
bool set_font(std::string_view font_path, unsigned int font_size) {
@ -116,7 +130,7 @@ namespace pimoroni {
return result;
}
pp_point_t text(std::string_view text, pp_mat3_t *t=nullptr);
pp_point_t text(std::string_view text, int max_width, int max_height, pp_mat3_t *t=nullptr);
void transform(pp_path_t *path, pp_mat3_t *t);
void transform(pp_poly_t *poly, pp_mat3_t *t);

Wyświetl plik

@ -61,10 +61,25 @@ typedef struct {
PP_COORD_TYPE f, t; // angle from and to
} ppp_arc_def;
typedef struct {
PP_COORD_TYPE x, y; // coordinates
int c; // number of points on star
PP_COORD_TYPE ro, ri; // outer and inner radius for points
PP_COORD_TYPE s; // stroke thickness (0 == filled)
} ppp_star_def;
typedef struct {
PP_COORD_TYPE x1, y1; // start point
PP_COORD_TYPE x2, y2; // end point
PP_COORD_TYPE s; // thickness
} ppp_line_def;
pp_poly_t* ppp_rect(ppp_rect_def d);
pp_poly_t* ppp_regular(ppp_regular_def d);
pp_poly_t* ppp_circle(ppp_circle_def d);
pp_poly_t* ppp_arc(ppp_arc_def d);
pp_poly_t* ppp_star(ppp_star_def d);
pp_poly_t* ppp_line(ppp_line_def d);
#ifdef __cplusplus
}
@ -176,6 +191,36 @@ pp_poly_t* ppp_arc(ppp_arc_def d) {
return poly;
}
pp_poly_t* ppp_star(ppp_star_def d) {
pp_poly_t *poly = pp_poly_new();
pp_path_t *path = pp_poly_add_path(poly);
pp_path_t *inner = d.s != 0.0f ? pp_poly_add_path(poly) : NULL;
for(int i = 0; i < d.c * 2; i++) {
float step = ((M_PI * 2) / (float)(d.c * 2)) * (float)i;
PP_COORD_TYPE r = i % 2 == 0 ? d.ro : d.ri;
pp_path_add_point(path, (pp_point_t){sin(step) * r + d.x, cos(step) * r + d.y});
if(inner) { // append the inner path
PP_COORD_TYPE ior = d.ro - (d.s * d.ro / d.ri);
PP_COORD_TYPE iir = d.ri - d.s;
PP_COORD_TYPE ir = i % 2 == 0 ? ior : iir;
pp_path_add_point(inner, (pp_point_t){sin(step) * ir + d.x, cos(step) * ir + d.y});
}
}
return poly;
}
pp_poly_t* ppp_line(ppp_line_def d) {
pp_poly_t *poly = pp_poly_new();
pp_path_t *path = pp_poly_add_path(poly);
// create a normalised perpendicular vector
pp_point_t v = {d.y2 - d.y1, d.x2 - d.x1};
float mag = sqrt(v.x * v.x + v.y * v.y);
v.x /= mag; v.y /= mag; v.x *= -(d.s / 2.0f); v.y *= (d.s / 2.0f);
pp_point_t points[] = {{d.x1 + v.x, d.y1 + v.y}, {d.x2 + v.x, d.y2 + v.y}, {d.x2 - v.x, d.y2 - v.y}, {d.x1 - v.x, d.y1 - v.y}};
pp_path_add_points(path, points, 4);
return poly;
}
#endif // PPP_IMPLEMENTATION
#endif // PPP_INCLUDE_H

Wyświetl plik

@ -40,10 +40,6 @@
#define PP_COORD_TYPE float
#endif
#ifndef PP_MAX_NODES_PER_SCANLINE
#define PP_MAX_NODES_PER_SCANLINE 16
#endif
#ifndef PP_TILE_BUFFER_SIZE
#define PP_TILE_BUFFER_SIZE 64
#endif
@ -131,12 +127,20 @@ extern pp_tile_callback_t _pp_tile_callback;
extern pp_antialias_t _pp_antialias;
extern pp_mat3_t *_pp_transform;
// Our parent scope might want to hold a pointer to these
// ie: MicroPython to avoid garbage collection
extern int32_t *pp_nodes;
extern uint32_t *pp_node_counts;
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h);
void pp_tile_callback(pp_tile_callback_t callback);
void pp_antialias(pp_antialias_t antialias);
pp_mat3_t *pp_transform(pp_mat3_t *transform);
void pp_render(pp_poly_t *polygon);
void pp_init(uint32_t max_nodes_per_scanline);
void pp_deinit();
#ifdef __cplusplus
}
@ -380,19 +384,33 @@ pp_rect_t pp_poly_bounds(pp_poly_t *p) {
return b;
}
uint32_t _pp_max_nodes_per_scanline = 0;
// buffer that each tile is rendered into before callback
// allocate one extra byte to allow a small optimization in the row renderer
// This allocates 4k up-front to ensure it's stored in Pico's RAM
// Rather than potentially allocating into PSRAM at runtime and trashing perf
uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
// polygon node buffer handles at most 16 line intersections per scanline
// is this enough for cjk/emoji? (requires a 2kB buffer)
int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];
int32_t *pp_nodes;
uint32_t *pp_node_counts;
uint8_t _pp_alpha_map_none[2] = {0, 255};
uint8_t _pp_alpha_map_x4[5] = {0, 63, 127, 190, 255};
uint8_t _pp_alpha_map_x16[17] = {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};
void pp_init(uint32_t max_nodes_per_scanline) {
_pp_max_nodes_per_scanline = max_nodes_per_scanline;
pp_nodes = (int32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * max_nodes_per_scanline * 2 * sizeof(int32_t));
pp_node_counts = (uint32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * sizeof(uint32_t));
}
void pp_deinit() {
PP_FREE(pp_nodes);
PP_FREE(pp_node_counts);
}
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h) {
_pp_clip = (pp_rect_t){.x = x, .y = y, .w = w, .h = h};
}
@ -482,7 +500,10 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
// }
// #else
// loop over scanlines
while(count--) {
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
// consume accumulated error
while(e > dy) {e -= dy; x += xinc;}
@ -490,7 +511,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
int nx = _pp_max(_pp_min(x, (tb->w << _pp_antialias)), 0);
//debug(" + adding node at %d, %d\n", x, y);
// add node to node list
pp_nodes[y][pp_node_counts[y]++] = nx;
pp_scanline_nodes[pp_node_counts[y]++] = nx;
// step to next scanline and accumulate error
y++;
@ -530,18 +551,19 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
debug(" + render tile %d, %d - %d, %d\n", tb->x, tb->y, tb->w, tb->h);
for(int y = 0; y < ((int)PP_TILE_BUFFER_SIZE << _pp_antialias); y++) {
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
// debug(" : row %d node count %d\n", y, pp_node_counts[y]);
if(pp_node_counts[y] == 0) continue; // no nodes on this raster line
qsort(&pp_nodes[y][0], pp_node_counts[y], sizeof(int), compare_nodes);
qsort(pp_scanline_nodes, pp_node_counts[y], sizeof(int), compare_nodes);
unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * PP_TILE_BUFFER_SIZE];
for(uint32_t i = 0; i < pp_node_counts[y]; i += 2) {
int sx = pp_nodes[y][i + 0];
int ex = pp_nodes[y][i + 1];
int sx = *pp_scanline_nodes++;
int ex = *pp_scanline_nodes++;
if(sx == ex) { // empty span, nothing to do
continue;
@ -570,14 +592,14 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
// either 1 (at x4) or 3 (at x16) we change that to a "ceil" instead ensuring
// the full tile bounds are returned
if(_pp_antialias) {
rb.w += (_pp_antialias | 0b1);
rb.h += (_pp_antialias | 0b1);
}
int maxx = rb.x + rb.w + (_pp_antialias | 0b1);
int maxy = rb.y + rb.h + (_pp_antialias | 0b1);
rb.x >>= _pp_antialias;
rb.y >>= _pp_antialias;
rb.w >>= _pp_antialias;
rb.h >>= _pp_antialias;
rb.x >>= _pp_antialias;
rb.y >>= _pp_antialias;
rb.w = (maxx >> _pp_antialias) - rb.x;
rb.h = (maxy >> _pp_antialias) - rb.y;
}
uint8_t *p_alpha_map = _pp_alpha_map_none;
if(_pp_antialias == 1) p_alpha_map = _pp_alpha_map_x4;
@ -636,8 +658,8 @@ void pp_render(pp_poly_t *polygon) {
if(pp_rect_empty(&tb)) { debug(" : empty when clipped, skipping\n"); continue; }
// clear existing tile data and nodes
memset(pp_node_counts, 0, sizeof(pp_node_counts));
memset(pp_tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE);
memset(pp_node_counts, 0, PP_TILE_BUFFER_SIZE * 4 * sizeof(uint32_t));
memset(pp_tile_buffer, 0, sizeof(pp_tile_buffer));
// build the nodes for each pp_path_t
pp_path_t *path = polygon->paths;

Wyświetl plik

@ -0,0 +1,20 @@
{
"deploy": [
"../deploy.md"
],
"docs": "",
"features": [
"Breadboard friendly",
"Castellated Pads",
"Micro USB"
],
"id": "rp2-pico",
"images": [
"rp2-pico.jpg"
],
"mcu": "rp2040",
"product": "Pico",
"thumbnail": "",
"url": "https://www.raspberrypi.com/products/raspberry-pi-pico/",
"vendor": "Raspberry Pi"
}

Wyświetl plik

@ -0,0 +1,7 @@
include("$(PORT_DIR)/boards/manifest.py")
require("bundle-networking")
include("../manifest_pico.py")
freeze("../../modules_py", "lte.py")

Wyświetl plik

@ -0,0 +1,9 @@
# cmake file for Raspberry Pi Pico
set(PICO_BOARD "pico")
set(MICROPY_PY_LWIP ON)
# Board specific version of the frozen manifest
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
set(MICROPY_C_HEAP_SIZE 4096)

Wyświetl plik

@ -0,0 +1,16 @@
// Board and hardware specific configuration
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
#define MICROPY_HW_FLASH_STORAGE_BYTES (1024 * 1024)
// Enable networking.
#define MICROPY_PY_NETWORK 1
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico"
#define MICROPY_PY_NETWORK_PPP_LWIP 1
#define MICROPY_HW_NIC_PPP { MP_ROM_QSTR(MP_QSTR_PINT), MP_ROM_PTR(&mp_network_ppp_lwip_type) },
#define MICROPY_BOARD_NETWORK_INTERFACES \
MICROPY_HW_NIC_PPP
#define MICROPY_PY_SOCKET_EXTENDED_STATE 1

Wyświetl plik

@ -0,0 +1,28 @@
GP0,GPIO0
GP1,GPIO1
GP2,GPIO2
GP3,GPIO3
GP4,GPIO4
GP5,GPIO5
GP6,GPIO6
GP7,GPIO7
GP8,GPIO8
GP9,GPIO9
GP10,GPIO10
GP11,GPIO11
GP12,GPIO12
GP13,GPIO13
GP14,GPIO14
GP15,GPIO15
GP16,GPIO16
GP17,GPIO17
GP18,GPIO18
GP19,GPIO19
GP20,GPIO20
GP21,GPIO21
GP22,GPIO22
GP25,GPIO25
GP26,GPIO26
GP27,GPIO27
GP28,GPIO28
LED,GPIO25
1 GP0 GPIO0
2 GP1 GPIO1
3 GP2 GPIO2
4 GP3 GPIO3
5 GP4 GPIO4
6 GP5 GPIO5
7 GP6 GPIO6
8 GP7 GPIO7
9 GP8 GPIO8
10 GP9 GPIO9
11 GP10 GPIO10
12 GP11 GPIO11
13 GP12 GPIO12
14 GP13 GPIO13
15 GP14 GPIO14
16 GP15 GPIO15
17 GP16 GPIO16
18 GP17 GPIO17
19 GP18 GPIO18
20 GP19 GPIO19
21 GP20 GPIO20
22 GP21 GPIO21
23 GP22 GPIO22
24 GP25 GPIO25
25 GP26 GPIO26
26 GP27 GPIO27
27 GP28 GPIO28
28 LED GPIO25

Wyświetl plik

@ -12,7 +12,7 @@ display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0)
display.set_backlight(0.8)
vsys = ADC(29) # reads the system input voltage
vsys = ADC(Pin(29)) # reads the system input voltage
charging = Pin(24, Pin.IN) # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535

Wyświetl plik

@ -13,7 +13,7 @@ display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0)
display.set_backlight(0.8)
vsys = ADC(29) # reads the system input voltage
vsys = ADC(Pin(29)) # reads the system input voltage
charging = Pin(24, Pin.IN) # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535

Wyświetl plik

@ -13,7 +13,7 @@ display = PicoGraphics(display=DISPLAY_PICO_EXPLORER)
buzzer = Buzzer(0)
vsys = ADC(29) # reads the system input voltage
vsys = ADC(Pin(29)) # reads the system input voltage
charging = Pin(24, Pin.IN) # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535

Wyświetl plik

@ -18,6 +18,9 @@ UPDATE_INTERVAL = 120 # refresh interval in secs. Be nice to free APIs!
# Set how many LEDs you have
NUM_LEDS = 50
# Set the brightness
BRIGHTNESS = 0.5
def status_handler(mode, status, ip):
# reports wifi connection status
@ -25,10 +28,10 @@ def status_handler(mode, status, ip):
print('Connecting to wifi...')
# flash while connecting
for i in range(NUM_LEDS):
led_strip.set_rgb(i, 255, 255, 255)
led_strip.set_hsv(i, 0, 0, BRIGHTNESS)
time.sleep(0.02)
for i in range(NUM_LEDS):
led_strip.set_rgb(i, 0, 0, 0)
led_strip.set_hsv(i, 0, 0, 0)
if status is not None:
if status:
print('Wifi connection successful!')
@ -52,7 +55,7 @@ def spooky_rainbows():
j = max(0, 1 - abs(distance - i) / (NUM_LEDS / 3))
hue = HUE_START + j * (HUE_END - HUE_START)
led_strip.set_hsv(i, hue / 360, 1.0, 0.8)
led_strip.set_hsv(i, hue / 360, 1.0, BRIGHTNESS)
# reverse direction at the end of colour segment to avoid an abrupt change
distance += direction
@ -109,6 +112,9 @@ while True:
# and convert it to RGB
r, g, b = hex_to_rgb(hex)
# adjust the brightness
r, g, b = (int(i * BRIGHTNESS) for i in (r, g, b))
# light up the LEDs
for i in range(NUM_LEDS):
led_strip.set_rgb(i, r, g, b)

Wyświetl plik

@ -32,9 +32,9 @@ button_a = Button(7, invert=False)
button_b = Button(8, invert=False)
# Pins and analogue-digital converters we need to set up to measure sensors.
lux_vref_pwr = Pin(27, Pin.OUT)
lux = ADC(26)
vbat_adc = ADC(29)
vref_adc = ADC(28)
lux = ADC(Pin(26))
vbat_adc = ADC(Pin(29))
vref_adc = ADC(Pin(28))
usb_power = Pin(24, Pin.IN)
display = PicoGraphics(display=DISPLAY_TUFTY_2040)

Wyświetl plik

@ -10,8 +10,8 @@ display = PicoGraphics(display=DISPLAY_TUFTY_2040)
display.set_backlight(0.8)
# set up the ADCs for measuring battery voltage
vbat_adc = ADC(29)
vref_adc = ADC(28)
vbat_adc = ADC(Pin(29))
vref_adc = ADC(Pin(28))
vref_en = Pin(27)
vref_en.init(Pin.OUT)
vref_en.value(0)

Wyświetl plik

@ -31,6 +31,9 @@ include(wakeup/micropython)
# Configure wakeup for Enviro
target_compile_definitions(usermod_wakeup INTERFACE
-DWAKEUP_HAS_RTC=1
-DWAKEUP_PIN_MASK=0b01000100
-DWAKEUP_PIN_DIR=0b01000100
-DWAKEUP_PIN_VALUE=0b01000100
)
# LEDs & Matrices

Wyświetl plik

@ -33,6 +33,9 @@ include(wakeup/micropython)
target_compile_definitions(usermod_wakeup INTERFACE
-DWAKEUP_HAS_RTC=1
-DWAKEUP_HAS_SHIFT_REGISTER=1
-DWAKEUP_PIN_MASK=0b01000100
-DWAKEUP_PIN_DIR=0b01000100
-DWAKEUP_PIN_VALUE=0b01000100
)
# LEDs & Matrices

Wyświetl plik

@ -0,0 +1,16 @@
include_directories(${CMAKE_CURRENT_LIST_DIR}/../../)
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)
# C++ Magic Memory
include(cppmem/micropython)
# Disable build-busting C++ exceptions
include(micropython-disable-exceptions)

Wyświetl plik

@ -164,6 +164,7 @@ static const mp_map_elem_t picographics_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X64), MP_ROM_INT(DISPLAY_INTERSTATE75_128X64) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_192X64), MP_ROM_INT(DISPLAY_INTERSTATE75_192X64) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_256X64), MP_ROM_INT(DISPLAY_INTERSTATE75_256X64) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X128), MP_ROM_INT(DISPLAY_INTERSTATE75_128X128) },
{ 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_STELLAR_UNICORN), MP_ROM_INT(DISPLAY_STELLAR_UNICORN) },
@ -172,6 +173,7 @@ static const mp_map_elem_t picographics_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_W_EXPLORER), MP_ROM_INT(DISPLAY_PICO_W_EXPLORER) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_EXPLORER), MP_ROM_INT(DISPLAY_EXPLORER) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PRESTO), MP_ROM_INT(DISPLAY_PRESTO) },
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PRESTO_FULL_RES), MP_ROM_INT(DISPLAY_PRESTO_FULL_RES) },
{ 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

@ -211,6 +211,14 @@ 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_INTERSTATE75_128X128:
width = 128;
height = 128;
bus_type = BUS_PIO;
// Portrait to match labelling
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB888;
break;
case DISPLAY_INKY_FRAME_7:
width = 800;
height = 480;
@ -254,7 +262,14 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
height = 240;
bus_type = BUS_PIO;
rotate = (int)Rotation::ROTATE_0;
pen_type = PEN_RGB565;
if(pen_type == -1) pen_type = PEN_RGB565;
break;
case DISPLAY_PRESTO_FULL_RES:
width = 480;
height = 480;
bus_type = BUS_PIO;
rotate = (int)Rotation::ROTATE_0;
if(pen_type == -1) pen_type = PEN_RGB565;
break;
default:
return false;
@ -397,7 +412,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|| display == DISPLAY_STELLAR_UNICORN
|| display == DISPLAY_UNICORN_PACK
|| display == DISPLAY_SCROLL_PACK
|| display == DISPLAY_PRESTO) {
|| display == DISPLAY_PRESTO
|| display == DISPLAY_PRESTO_FULL_RES) {
// Create a dummy display driver
self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate);

Wyświetl plik

@ -25,6 +25,7 @@ enum PicoGraphicsDisplay {
DISPLAY_INTERSTATE75_128X64,
DISPLAY_INTERSTATE75_192X64,
DISPLAY_INTERSTATE75_256X64,
DISPLAY_INTERSTATE75_128X128,
DISPLAY_INKY_FRAME_7,
DISPLAY_COSMIC_UNICORN,
DISPLAY_STELLAR_UNICORN,
@ -32,7 +33,8 @@ enum PicoGraphicsDisplay {
DISPLAY_SCROLL_PACK,
DISPLAY_PICO_W_EXPLORER,
DISPLAY_EXPLORER,
DISPLAY_PRESTO
DISPLAY_PRESTO,
DISPLAY_PRESTO_FULL_RES
};
enum PicoGraphicsPenType {

Wyświetl plik

@ -19,6 +19,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR(POLYGON_path_obj, 4, POLYGON_path);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_regular_obj, 5, POLYGON_regular);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_circle_obj, 4, POLYGON_circle);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_arc_obj, 6, POLYGON_arc);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_star_obj, 6, POLYGON_star);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_line_obj, 5, POLYGON_line);
static const mp_rom_map_elem_t POLYGON_locals_dict_table[] = {
@ -39,6 +41,8 @@ static const mp_rom_map_elem_t POLYGON_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&POLYGON_path_obj) },
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&POLYGON_circle_obj) },
{ MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&POLYGON_arc_obj) },
{ MP_ROM_QSTR(MP_QSTR_star), MP_ROM_PTR(&POLYGON_star_obj) },
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&POLYGON_line_obj) },
};
static MP_DEFINE_CONST_DICT(POLYGON_locals_dict, POLYGON_locals_dict_table);

Wyświetl plik

@ -21,7 +21,6 @@ typedef struct _ModPicoGraphics_obj_t {
typedef struct _VECTOR_obj_t {
mp_obj_base_t base;
void *mem;
PicoVector *vector;
} _VECTOR_obj_t;
@ -352,6 +351,72 @@ mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
return self;
}
mp_obj_t POLYGON_star(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_points, ARG_inner_radius, ARG_outer_radius, ARG_stroke };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_inner_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_outer_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
picovector_point_type x = mp_picovector_get_point_type(args[ARG_x].u_obj);
picovector_point_type y = mp_picovector_get_point_type(args[ARG_y].u_obj);
int p = args[ARG_points].u_int;
picovector_point_type r1 = mp_picovector_get_point_type(args[ARG_inner_radius].u_obj);
picovector_point_type r2 = mp_picovector_get_point_type(args[ARG_outer_radius].u_obj);
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
pp_poly_merge(self->poly, ppp_star({
x, y,
p,
r1,
r2,
s
}));
return self;
}
mp_obj_t POLYGON_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_x2, ARG_y2, ARG_thickness };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_thickness, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
picovector_point_type x = mp_picovector_get_point_type(args[ARG_x].u_obj);
picovector_point_type y = mp_picovector_get_point_type(args[ARG_y].u_obj);
picovector_point_type x2 = mp_picovector_get_point_type(args[ARG_x2].u_obj);
picovector_point_type y2 = mp_picovector_get_point_type(args[ARG_y2].u_obj);
picovector_point_type t = args[ARG_thickness].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_thickness].u_obj);
pp_poly_merge(self->poly, ppp_line({
x, y,
x2, y2,
t
}));
return self;
}
// Utility functions
mp_obj_t POLYGON_centroid(mp_obj_t self_in) {
@ -545,12 +610,7 @@ mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
self->base.type = &VECTOR_type;
ModPicoGraphics_obj_t *graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj);
// The PicoVector class calls `pretty_poly::init()` with the memory region
// it does not store a pointer to this, so we need to store one ourselves
// TODO: C Pretty Poly does not support runtime memory allocation
//self->mem = m_new(uint8_t, PicoVector::pretty_poly_buffer_size());
self->vector = m_new_class(PicoVector, graphics->graphics, self->mem);
self->vector = m_new_class(PicoVector, graphics->graphics);
return self;
}
@ -705,13 +765,15 @@ mp_obj_t VECTOR_set_antialiasing(mp_obj_t self_in, mp_obj_t aa) {
}
mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_angle };
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_angle, ARG_max_width, ARG_max_height };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} }
{ MP_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_max_width, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_max_height, MP_ARG_INT, {.u_int = 0} }
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -729,6 +791,8 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
int x = args[ARG_x].u_int;
int y = args[ARG_y].u_int;
int max_width = args[ARG_max_width].u_int;
int max_height = args[ARG_max_height].u_int;
pp_mat3_t tt = pp_mat3_identity();
@ -738,7 +802,7 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
pp_mat3_translate(&tt, (float)x, (float)y);
self->vector->text(t, &tt);
self->vector->text(t, max_width, max_height, &tt);
return mp_const_none;
}

Wyświetl plik

@ -13,6 +13,8 @@ extern mp_obj_t POLYGON_regular(size_t n_args, const mp_obj_t *pos_args, mp_map_
extern mp_obj_t POLYGON_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_star(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t POLYGON_centroid(mp_obj_t self_in);

Wyświetl plik

@ -5,7 +5,6 @@ add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
#${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.S
)
target_include_directories(usermod_${MOD_NAME} INTERFACE

Wyświetl plik

@ -1,36 +0,0 @@
.syntax unified
.cpu cortex-m0plus
.thumb
#include "pico/asm_helper.S"
// This macro tells the pico runtime to call __wakeup_gpio_latch very early in boot
__pre_init __wakeup_gpio_latch, 00000
.section .data.wakeup_gpio_latch
.global wakeup_gpio_state
.align 4
wakeup_gpio_state:
.word 0x00000000
.section .text
.thumb_func
__wakeup_gpio_latch:
// Read GPIO state for front buttons and store
movs r3, 0xd0 // Load 0xd0 into r3
lsls r3, r3, 24 // Shift left 24 to get 0xd0000000
ldr r1, [r3, 4] // Load GPIO state (0xd0000004) into r1
ldr r2, =wakeup_gpio_state // Load output var addr into r2
str r1, [r2] // Store r1 to r2
// Enable 3v3 pin on the badger
ldr r1, =0x40014054 // GPIO control register 10
movs r2, 5 // SIO function
str r2, [r1] // Set Enable 3v3 to SIO // https://github.com/raspberrypi/pico-sdk/blob/2e6142b15b8a75c1227dd3edbe839193b2bf9041/src/rp2_common/hardware_gpio/include/hardware/gpio.h#L96
str r2, [r1, 120] // Also set LED (25) to SIO
ldr r2, =0x02000400 // Pins 25 and 10
str r2, [r3, 36] // Enable pins out
str r2, [r3, 20] // Set pins high
bx lr // Return

Wyświetl plik

@ -1,18 +1,30 @@
#include "hardware/gpio.h"
#include "wakeup.config.hpp"
extern uint32_t runtime_wakeup_gpio_state;
namespace {
struct Wakeup {
public:
uint8_t shift_register_state = 0b0;
uint32_t gpio_state = 0;
Wakeup() {
// Assert wakeup pins (indicator LEDs, VSYS hold etc)
//gpio_init_mask(WAKEUP_PIN_MASK);
//gpio_set_dir_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_DIR);
//gpio_put_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_VALUE);
gpio_init_mask(WAKEUP_PIN_MASK);
gpio_set_dir_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_DIR);
gpio_put_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_VALUE);
// Init all GPIOS not specified in the wakeup mask
#if PICO_RP2350
gpio_init_mask(~WAKEUP_PIN_MASK);
gpio_set_dir_in_masked(~WAKEUP_PIN_MASK);
#endif
gpio_state = gpio_get_all();
sleep_ms(5);
gpio_state |= gpio_get_all();
#if PICO_RP2350
gpio_init_mask(~WAKEUP_PIN_MASK);
#endif
#if WAKEUP_HAS_RTC==1
// Set up RTC I2C pins and send reset command
@ -59,11 +71,11 @@ extern "C" {
#include "wakeup.h"
mp_obj_t Wakeup_get_gpio_state() {
return mp_obj_new_int(runtime_wakeup_gpio_state);
return mp_obj_new_int(wakeup.gpio_state);
}
mp_obj_t Wakeup_reset_gpio_state() {
runtime_wakeup_gpio_state = 0;
wakeup.gpio_state = 0;
return mp_const_none;
}

Wyświetl plik

@ -1,5 +1,5 @@
from pimoroni import RGBLED, Button
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_96X48, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_96X48, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64, DISPLAY_INTERSTATE75_128X128
from pimoroni_i2c import PimoroniI2C
import hub75
import sys
@ -29,6 +29,7 @@ class Interstate75:
DISPLAY_INTERSTATE75_128X64 = DISPLAY_INTERSTATE75_128X64
DISPLAY_INTERSTATE75_192X64 = DISPLAY_INTERSTATE75_192X64
DISPLAY_INTERSTATE75_256X64 = DISPLAY_INTERSTATE75_256X64
DISPLAY_INTERSTATE75_128X128 = DISPLAY_INTERSTATE75_128X128
PANEL_GENERIC = hub75.PANEL_GENERIC
PANEL_FM6126A = hub75.PANEL_FM6126A
@ -46,7 +47,15 @@ class Interstate75:
self.interstate75w = "Pico W" in sys.implementation._machine
self.display = PicoGraphics(display=display)
self.width, self.height = self.display.get_bounds()
self.hub75 = hub75.Hub75(self.width, self.height, panel_type=panel_type, stb_invert=stb_invert, color_order=color_order)
out_width = self.width
out_height = self.height
if display == DISPLAY_INTERSTATE75_128X128:
out_width = 256
out_height = 64
self.hub75 = hub75.Hub75(out_width, out_height, panel_type=panel_type, stb_invert=stb_invert, color_order=color_order)
self.hub75.start()
if self.interstate75w:
self._switch_pins = self.SWITCH_PINS_W

Wyświetl plik

@ -0,0 +1,205 @@
import time
from machine import UART, Pin
from network import PPP
from micropython import const
DEFAULT_PIN_RST = 35
DEFAULT_PIN_NETLIGHT = 34
DEFAULT_PIN_RX = 33
DEFAULT_PIN_TX = 32
DEFAULT_UART_ID = 0
DEFAULT_UART_TIMEOUT = const(1)
DEFAULT_UART_TIMEOUT_CHAR = const(1)
DEFAULT_UART_RXBUF = const(1024)
DEFAULT_UART_STARTUP_BAUD = const(115200)
DEFAULT_UART_BAUD = const(460800)
class CellularError(Exception):
def __init__(self, message=None):
self.message = "CellularError: " + message
class LTE():
def __init__(self, apn, uart=None, reset_pin=None, netlight_pin=None, netlight_led=None, skip_reset=False):
self._apn = apn
self._reset = reset_pin or Pin(DEFAULT_PIN_RST, Pin.OUT)
self._uart = uart or UART(
DEFAULT_UART_ID,
tx=Pin(DEFAULT_PIN_TX, Pin.OUT),
rx=Pin(DEFAULT_PIN_RX, Pin.OUT))
# Set PPP timeouts and rxbuf
self._uart.init(
timeout=DEFAULT_UART_TIMEOUT,
timeout_char=DEFAULT_UART_TIMEOUT_CHAR,
rxbuf=DEFAULT_UART_RXBUF)
if not skip_reset:
self._reset.value(0)
time.sleep(1.0)
self._reset.value(1)
if netlight_led:
self._led = netlight_led
self._netlight = netlight_pin or Pin(DEFAULT_PIN_NETLIGHT, Pin.IN)
self._netlight.irq(self._netlight_irq)
def _netlight_irq(self, pin):
self._led.value(pin.value())
def ipconfig(self, *args, **kwargs):
if len(args):
return self._ppp.ipconfig(*args)
else:
return self._ppp.ipconfig(**kwargs)
def iccid(self):
try:
return self._send_at_command("AT+CICCID", 1)
except CellularError:
return None
def status(self):
lte_status = self._send_at_command("AT+CEREG?", 1)
gsm_status = self._send_at_command("AT+CGREG?", 1)
return lte_status, gsm_status
def signal_quality(self):
try:
response = self._send_at_command("AT+CSQ", 1)
quality = int(response.split(":")[1].split(",")[0])
# Conversion as per AT command set datasheet
db = -113 + (2 * quality)
return db
except CellularError:
pass
return None
def stop_ppp(self):
self._ppp.disconnect()
self._send_at_command(f"AT+IPR={DEFAULT_UART_STARTUP_BAUD}")
self._flush_uart()
def start_ppp(self, baudrate=DEFAULT_UART_BAUD, connect=True):
self._wait_ready(poll_time=1.0, timeout=30)
# Switch to a faster baudrate
self._send_at_command(f"AT+IPR={baudrate}")
self._flush_uart()
self._uart.init(
baudrate=baudrate,
timeout=DEFAULT_UART_TIMEOUT,
timeout_char=DEFAULT_UART_TIMEOUT_CHAR,
rxbuf=DEFAULT_UART_RXBUF)
self._wait_ready(poll_time=1.0)
# Connect!
if connect:
self.connect()
# Force PPP to use modem's default settings...
self._flush_uart()
self._uart.write("ATD*99#\r")
self._uart.flush()
self._ppp = PPP(self._uart)
self._ppp.connect()
while self._ppp.status() != 4:
time.sleep(1.0)
return self._ppp.ifconfig()
def connect(self, timeout=60):
print(" - setting up cellular uart")
# Connect to and flush the uart
# Discard any unsolicited messages first, we don't need those
self._flush_uart()
print(" - waiting for cellular module to be ready")
# Wait for the cellular module to respond to AT commands
self._wait_ready()
self._send_at_command("ATE0") # Disable local echo
self._send_at_command(f"AT+CGDCONT=1,\"IP\",\"{self._apn}\"") # Set apn and activate pdp context
# Wait for roaming lte connection to be established
giveup = time.time() + timeout
status = None
while status != "+CEREG: 0,5" and status != "+CEREG: 0,1":
status = self._send_at_command("AT+CEREG?", 1)
time.sleep(0.25)
if time.time() > giveup:
raise CellularError("timed out getting network registration")
# Disable server and client certification validation
self._send_at_command("AT+CSSLCFG=\"authmode\",0,0")
self._send_at_command("AT+CSSLCFG=\"enableSNI\",0,1")
print(f" - SIM ICCID is {self.iccid()}")
def _wait_ready(self, poll_time=0.25, timeout=10):
giveup = time.time() + timeout
while time.time() <= giveup:
try:
self._send_at_command("AT")
return # If __send_at_command doesn't throw an exception then we're good!
except CellularError as e:
print(e)
time.sleep(poll_time)
raise CellularError("timed out waiting for AT response")
def _flush_uart(self):
self._uart.flush()
time.sleep(0.25)
while self._uart.any():
self._uart.read(self._uart.any())
time.sleep(0.25)
def _send_at_command(self, command, result_lines=0, timeout=5.0):
# Discard any unsolicited messages first, we don't need those
self._flush_uart()
self._uart.write(command + "\r")
self._uart.flush()
status, data = self._read_result(result_lines, timeout=timeout)
print(" -", command, status, data)
if status == "TIMEOUT":
raise CellularError(f"cellular module timed out for command {command}")
if status not in ["OK", "DOWNLOAD"]:
raise CellularError(f"non 'OK' or 'DOWNLOAD' result for command {command}")
if result_lines == 1:
return data[0]
if result_lines > 1:
return data
return None
def _read_result(self, result_lines, timeout=1.0):
status = None
result = []
start = time.ticks_ms()
timeout *= 1000
while len(result) < result_lines or status is None:
if (time.ticks_ms() - start) > timeout:
return "TIMEOUT", []
line = self._uart.readline()
if line:
line = line.strip()
if line in [b"OK", b"ERROR", b"DOWNLOAD"]:
status = line.decode("ascii")
elif line != b"":
result.append(str(line, "ascii"))
start = time.ticks_ms()
return status, result