Skip to content

Commit

Permalink
MicroPython: Avoid heap usage.
Browse files Browse the repository at this point in the history
* Use string_view in lieu of string
* Rewrite _parse_escape_code to be compatible with string_view
* Allocate a static buffer_t _SCREEN if DYNAMIC_BUFFER not set
  • Loading branch information
Gadgetoid committed Mar 15, 2023
1 parent 639c1d2 commit d5a56db
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 23 deletions.
21 changes: 18 additions & 3 deletions libraries/picosystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,22 @@ namespace picosystem {
#ifndef DYNAMIC_BUFFER
#ifdef PIXEL_DOUBLE
color_t _fb[120 * 120] __attribute__ ((aligned (4))) = { };
buffer_t *SCREEN = buffer(120, 120, _fb);
buffer_t _SCREEN = {
.w = 120,
.h = 120,
.data = (color_t *)&_fb
};
int32_t _cx = 0, _cy = 0, _cw = 120, _ch = 120;
buffer_t *SCREEN = &_SCREEN;
#else
color_t _fb[240 * 240] __attribute__ ((aligned (4))) = { };
buffer_t *SCREEN = buffer(240, 240, _fb);
buffer_t _SCREEN = {
.w = 240,
.h = 240,
.data = (color_t *)&_fb
};
int32_t _cx = 0, _cy = 0, _cw = 240, _ch = 240;
buffer_t *SCREEN = &_SCREEN;
#endif
#else
buffer_t *SCREEN = nullptr;
Expand All @@ -41,7 +51,12 @@ namespace picosystem {
#ifdef NO_SPRITESHEET
buffer_t *_ss = nullptr;
#else
buffer_t *SPRITESHEET = buffer(128, 128, (void *)_default_sprite_sheet);
buffer_t _SPRITESHEET = {
.w = 128,
.h = 128,
.data = (color_t *)_default_sprite_sheet
};
buffer_t *SPRITESHEET = &_SPRITESHEET;
buffer_t *_ss = SPRITESHEET;
#endif

Expand Down
10 changes: 6 additions & 4 deletions libraries/picosystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <initializer_list>

#include <string>
#include <string_view>
#include <vector>
#include <charconv>

#include "pico/stdlib.h"

Expand Down Expand Up @@ -139,11 +141,11 @@ namespace picosystem {
int32_t dw, int32_t dh, uint32_t flags);
void text(const char &c);
void text(
const std::string &t,
const std::string_view &t,
int32_t x, int32_t y,
int32_t wrap = -1);
void text(
const std::string &t,
const std::string_view &t,
int32_t wrap = -1);

// blend functions
Expand Down Expand Up @@ -205,10 +207,10 @@ namespace picosystem {
int32_t x, int32_t y, int32_t w, int32_t h,
int32_t cx, int32_t cy, int32_t cw, int32_t ch);
void measure(
const std::string &t,
const std::string_view &t,
int32_t &w, int32_t &h,
int32_t wrap = -1);
std::vector<std::string> split(const std::string& t, char d = '\n');
std::vector<std::string_view> split(const std::string_view& t, char d = '\n');
float fsin(float v);
float fcos(float v);
color_t mix(color_t c1, color_t c2, uint8_t m);
Expand Down
27 changes: 15 additions & 12 deletions libraries/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace picosystem {
_tx += _char_width(c) + _tls;
}

bool _matches(const std::string &t, const std::string &m, std::size_t &i) {
bool _matches(const std::string_view &t, const std::string_view &m, std::size_t &i) {
std::size_t j = 0;
while(j < m.size()) {
if(t[i + j] != m[j]) {
Expand All @@ -46,7 +46,7 @@ namespace picosystem {
return true;
}

uint32_t _skip_escape_code(const std::string &t, std::size_t &i) {
uint32_t _skip_escape_code(const std::string_view &t, std::size_t &i) {
uint32_t l = 0;
i++;
if(_matches(t, "pen", i)) {
Expand All @@ -60,7 +60,7 @@ namespace picosystem {
}

// search for end of the next word (including any e)
uint32_t _next_word_length(const std::string &t, std::size_t i) {
uint32_t _next_word_length(const std::string_view &t, std::size_t i) {
// search through until we find a non word character to break on
uint32_t l = 0;
while(true) {
Expand All @@ -86,8 +86,8 @@ namespace picosystem {
return 0;
}

void _parse_escape_code(const std::string &t, std::size_t &i) {
i++;
void _parse_escape_code(const std::string_view &t, std::size_t &i) {
i++; // Skip the escape character
if (_matches(t, "pen", i) ){
uint8_t r = _hex_to_int(t[i++]);
uint8_t g = _hex_to_int(t[i++]);
Expand All @@ -97,14 +97,17 @@ namespace picosystem {
}

if (_matches(t, "spr", i) ){
uint8_t si = std::stoi(t.substr(i, 3));
i += 2;
sprite(si, _tx, _ty);
_tx += 8;
uint8_t si;
auto result = std::from_chars(t.data() + i, t.data() + t.size(), si);
if(result.ec != std::errc::invalid_argument && result.ec != std::errc::result_out_of_range) {
i += result.ptr - t.data();
sprite(si, _tx, _ty);
_tx += 8;
}
}
}

void measure(const std::string &t, int32_t &w, int32_t &h, int32_t wrap) {
void measure(const std::string_view &t, int32_t &w, int32_t &h, int32_t wrap) {
w = 0; h = 0;

// save cursor position for wrapping new lines
Expand Down Expand Up @@ -155,7 +158,7 @@ namespace picosystem {
h = ty + _tlh;
}

void text(const std::string &t, int32_t wrap) {
void text(const std::string_view &t, int32_t wrap) {
// save cursor position for wrapping new lines
int32_t _stx = _tx;
int32_t _wtx = _tx + wrap;
Expand Down Expand Up @@ -205,7 +208,7 @@ namespace picosystem {
_tx = _stx;
}

void text(const std::string &t, int32_t x, int32_t y, int32_t wrap) {
void text(const std::string_view &t, int32_t x, int32_t y, int32_t wrap) {
_camera_offset(x, y);
_tx = x; _ty = y;
text(t, wrap);
Expand Down
4 changes: 4 additions & 0 deletions micropython/modules/micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/../../)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")

# Enable support for string_view
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

include(picosystem/micropython)
7 changes: 7 additions & 0 deletions micropython/modules/picosystem/micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ target_include_directories(usermod_picosystem INTERFACE
target_compile_definitions(usermod_picosystem INTERFACE
MODULE_PICOSYSTEM_ENABLED=1
PIXEL_DOUBLE=1
NO_OVERCLOCK=1
)

target_link_libraries(usermod_picosystem INTERFACE
Expand All @@ -52,6 +53,12 @@ set_source_files_properties(
"-DPIXEL_DOUBLE=1"
)

set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/hardware.cpp
PROPERTIES COMPILE_FLAGS
"-DNO_OVERCLOCK=1"
)

# TODO fix sign compare issues in codebase
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/primitives.cpp
Expand Down
4 changes: 2 additions & 2 deletions micropython/modules/picosystem/primitives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ mp_obj_t picosystem_poly(mp_uint_t n_args, const mp_obj_t *args) {

if(num_tuples > 0) {
size_t num_points = num_tuples * 2;
int32_t* points = new int32_t[num_points];
int32_t* points = m_new(int32_t, num_points);
size_t i2 = 0;
for(size_t i = 0; i < num_tuples; i++) {
mp_obj_t obj = tuples[i];
Expand All @@ -152,7 +152,7 @@ mp_obj_t picosystem_poly(mp_uint_t n_args, const mp_obj_t *args) {
}
}
poly(points, num_tuples);
delete[] points;
m_free(points);
}

return mp_const_none;
Expand Down
4 changes: 2 additions & 2 deletions micropython/modules/picosystem/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mp_obj_t picosystem_text(mp_uint_t n_args, const mp_obj_t *args) {
if(mp_obj_is_str_or_bytes(args[0])) {
GET_STR_DATA_LEN(args[0], str, str_len);

std::string t((const char*)str);
std::string_view t((const char*)str, str_len);

if(n_args == 4) {
int x = mp_obj_get_int(args[1]);
Expand Down Expand Up @@ -46,7 +46,7 @@ mp_obj_t picosystem_measure(mp_uint_t n_args, const mp_obj_t *args) {
if(mp_obj_is_str_or_bytes(str_obj)) {
GET_STR_DATA_LEN(str_obj, str, str_len);

std::string t((const char*)str);
std::string_view t((const char*)str, str_len);
int32_t w = 0;
int32_t h = 0;
int32_t wrap = n_args == 2 ? mp_obj_get_int(args[1]) : -1;
Expand Down

0 comments on commit d5a56db

Please sign in to comment.