kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Porównaj commity
32 Commity
6e27957728
...
1a0a83ebd1
Autor | SHA1 | Data |
---|---|---|
Philip Howard | 1a0a83ebd1 | |
Phil Howard | 34b8b4d81f | |
Phil Howard | a2c48a8f44 | |
Mike Bell | c1e0631102 | |
Jonathan Williamson | c91b498505 | |
Philip Howard | be3e7ba83a | |
Phil Howard | b6f657f9fc | |
Phil Howard | c08f496ecf | |
Phil Howard | ad5120a8d2 | |
Mike Bell | 18d3ed3940 | |
Phil Howard | acf6e517f6 | |
Phil Howard | 896353af11 | |
Phil Howard | b184475bc0 | |
Phil Howard | d8c6883fc0 | |
Phil Howard | adfa429d47 | |
Phil Howard | d44f00886b | |
Mike Bell | 5f08e113bd | |
Mike Bell | 0807dc6810 | |
Mike Bell | 8471580c71 | |
Phil Howard | 6b0195a00b | |
Phil Howard | ab81c5df56 | |
Philip Howard | 1495805d2b | |
Philip Howard | fd4b2922e4 | |
Philip Howard | b8f4bd3f67 | |
Phil Howard | ef936ba907 | |
Phil Howard | a1be7a6327 | |
Phil Howard | a05a225262 | |
Phil Howard | 6cfcd80037 | |
Phil Howard | 81455d129d | |
Phil Howard | d24c2225ca | |
Hel Gibbons | b5d496bc90 | |
Hel Gibbons | 6264b96efe |
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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};
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
|
||||
require("bundle-networking")
|
||||
|
||||
include("../manifest_pico.py")
|
||||
|
||||
freeze("../../modules_py", "lte.py")
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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) },
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Ładowanie…
Reference in New Issue