Skip to content

Commit 372abff

Browse files
committed
Merge latest firmware + 0.1.2a
2 parents 7cafd0e + 3061ab1 commit 372abff

97 files changed

Lines changed: 5811 additions & 4546 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,16 @@ jobs:
188188
uses: actions/checkout@v4
189189
with:
190190
submodules: true
191+
- name: Setup poetry
192+
run: |
193+
pipx install poetry
194+
poetry install --only=build
191195
- name: Build
192196
run: |
193-
make $MAKEOPTS -C lib/pbio/test
197+
poetry run make $MAKEOPTS -C lib/pbio/test
194198
- name: Build docs
195199
run: |
196200
make $MAKEOPTS -C lib/pbio/doc
197201
- name: Build coverage
198202
run: |
199-
make $MAKEOPTS -C lib/pbio/test build-coverage/lcov.info
203+
poetry run make $MAKEOPTS -C lib/pbio/test build-coverage/lcov.info

.vscode/c_cpp_properties.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@
356356
"-fsingle-precision-constant"
357357
],
358358
"cStandard": "c11",
359-
"intelliSenseMode": "gcc-arm"
359+
"intelliSenseMode": "gcc-arm",
360+
"compilerPath": "arm-none-eabi-gcc"
360361
},
361362
{
362363
"name": "pbio/test",

CHANGELOG.md

Lines changed: 8 additions & 1353 deletions
Large diffs are not rendered by default.

bricks/_common/common.mk

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ PYDFU = $(TOP)/tools/pydfu.py
166166
PYBRICKSDEV = pybricksdev
167167
METADATA = $(PBTOP)/tools/metadata.py
168168
MEDIA_CONVERT = $(PBTOP)/lib/pbio/src/image/media.py
169+
FONT_CONVERT = $(PBTOP)/lib/pbio/src/image/fontconvert.py
169170
CREDITS_CONVERT = $(PBTOP)/bricks/ev3/make_credits.py
170171
OPENOCD ?= openocd
171172
OPENOCD_CONFIG ?= openocd_stm32$(PB_MCU_SERIES_LCASE).cfg
@@ -528,12 +529,68 @@ ifneq ($(PB_MCU_FAMILY),TIAM1808)
528529
SRC_S += lib/pbio/platform/$(PBIO_PLATFORM)/startup.s
529530
endif
530531

532+
vpath %.bmp $(PBTOP)
533+
vpath %.jpg $(PBTOP)
534+
vpath %.png $(PBTOP)
535+
vpath %.svg $(PBTOP)
536+
MEDIA_SRC = $(sort $(addprefix lib/pbio/src/image/media/,\
537+
lms2012/_app_ir_control_12.bmp \
538+
lms2012/_app_ir_control_34.bmp \
539+
lms2012/_app_motor_control_ad.bmp \
540+
lms2012/_app_motor_control_bc.bmp \
541+
lms2012/_port_view_empty.bmp \
542+
lms2012/_port_view_ev3_color_ambient.bmp \
543+
lms2012/_port_view_ev3_color_color.bmp \
544+
lms2012/_port_view_ev3_color_reflection.bmp \
545+
lms2012/_port_view_ev3_gyro.bmp \
546+
lms2012/_port_view_ev3_ir_beacon.bmp \
547+
lms2012/_port_view_ev3_ir_button.bmp \
548+
lms2012/_port_view_ev3_ir_proximity.bmp \
549+
lms2012/_port_view_ev3_motor_large.bmp \
550+
lms2012/_port_view_ev3_motor_medium.bmp \
551+
lms2012/_port_view_ev3_touch.bmp \
552+
lms2012/_port_view_ev3_ultrasonic.bmp \
553+
lms2012/_port_view_p0_bottom.bmp \
554+
lms2012/_port_view_p0_top.bmp \
555+
lms2012/_port_view_p1.bmp \
556+
lms2012/_port_view_p2.bmp \
557+
lms2012/_port_view_p3.bmp \
558+
lms2012/_port_view_p4.bmp \
559+
lms2012/_port_view_pa.bmp \
560+
lms2012/_port_view_pb.bmp \
561+
lms2012/_port_view_pc.bmp \
562+
lms2012/_port_view_pd.bmp \
563+
ui/_accept24.svg \
564+
ui/_accept24_fill.svg \
565+
ui/_off20.svg \
566+
ui/_port_view_nxt_color_ambient.svg \
567+
ui/_port_view_nxt_color_color.svg \
568+
ui/_port_view_nxt_color_reflection.svg \
569+
ui/_port_view_nxt_light_ambient.svg \
570+
ui/_port_view_nxt_light_reflection.svg \
571+
ui/_port_view_nxt_sound.svg \
572+
ui/_pybricks_join.png \
573+
ui/_reject24.svg \
574+
ui/_reject24_fill.svg \
575+
ui/_rotate_ccw18.svg \
576+
ui/_rotate_cw18.svg \
577+
ui/_usb_host.svg \
578+
ui/_wrench17.svg \
579+
))
580+
MEDIA_GEN_C = $(patsubst lib/pbio/src/image/media/%, $(BUILD)/media/%.c, $(basename $(MEDIA_SRC)))
581+
531582
ifeq ($(PB_MEDIA),1)
532583
PYBRICKS_PYBRICKS_SRC_C += $(BUILD)/pb_type_image_attributes.c
533-
PBIO_SRC_C += $(BUILD)/pbio_image_media.c
584+
PBIO_SRC_C += $(MEDIA_GEN_C)
534585
PBIO_SRC_C += $(BUILD)/hmi_ev3_ui_credits.c
535586
endif
536587

588+
ifeq ($(PB_FONTS),1)
589+
PBIO_SRC_C += $(BUILD)/font_liberationsans_regular_14.c
590+
PBIO_SRC_C += $(BUILD)/font_terminus_normal_16.c
591+
PBIO_SRC_C += $(BUILD)/font_mono_8x5_8.c
592+
endif
593+
537594
OBJ = $(PY_O)
538595
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
539596
OBJ += $(addprefix $(BUILD)/, $(PY_EXTRA_SRC_C:.c=.o))
@@ -637,9 +694,50 @@ else
637694
FW_SECTIONS :=
638695
endif
639696

640-
$(BUILD)/pbio_image_media.c $(BUILD)/pb_type_image_attributes.c: $(MEDIA_CONVERT)
697+
# Force media list regeneration if list of media sources changed.
698+
-include $(BUILD)/media_src_gen.mk
699+
MEDIA_REGEN := $(if $(strip $(filter-out $(MEDIA_SRC),$(MEDIA_SRC_GEN)) $(filter-out $(MEDIA_SRC_GEN),$(MEDIA_SRC))),media-regen)
700+
media-regen:
701+
.PHONY: media-regen
702+
.SECONDARY: $(MEDIA_GEN_C)
703+
704+
$(BUILD)/media/%.c: lib/pbio/src/image/media/%.bmp $(MEDIA_CONVERT)
705+
$(ECHO) "GEN $@"
706+
$(Q)mkdir -p $(dir $@)
707+
$(Q)$(PYTHON) $(MEDIA_CONVERT) -o $@ $<
708+
709+
$(BUILD)/media/%.c: lib/pbio/src/image/media/%.jpg $(MEDIA_CONVERT)
710+
$(ECHO) "GEN $@"
711+
$(Q)mkdir -p $(dir $@)
712+
$(Q)$(PYTHON) $(MEDIA_CONVERT) -o $@ $<
713+
714+
$(BUILD)/media/%.c: lib/pbio/src/image/media/%.png $(MEDIA_CONVERT)
715+
$(ECHO) "GEN $@"
716+
$(Q)mkdir -p $(dir $@)
717+
$(Q)$(PYTHON) $(MEDIA_CONVERT) -o $@ $<
718+
719+
$(BUILD)/media/%.c: lib/pbio/src/image/media/%.svg $(MEDIA_CONVERT)
720+
$(ECHO) "GEN $@"
721+
$(Q)mkdir -p $(dir $@)
722+
$(Q)$(PYTHON) $(MEDIA_CONVERT) -o $@ $<
723+
724+
$(BUILD)/pbio_image_media.h $(BUILD)/pb_type_image_attributes.c &: $(MEDIA_CONVERT) $(MEDIA_REGEN)
641725
$(ECHO) "Generating image media files"
642-
$(Q)$(PYTHON) $(MEDIA_CONVERT) $(BUILD)
726+
$(Q)mkdir -p $(BUILD)
727+
$(Q)$(PYTHON) $(MEDIA_CONVERT) --decls $(BUILD)/pbio_image_media.h --attrs $(BUILD)/pb_type_image_attributes.c $(MEDIA_SRC)
728+
$(ECHO) "MEDIA_SRC_GEN = $(MEDIA_SRC)" > $(BUILD)/media_src_gen.mk
729+
730+
$(BUILD)/font_liberationsans_regular_14.c: $(PBTOP)/lib/pbio/src/image/fonts/LiberationSans-Regular.ttf $(FONT_CONVERT)
731+
$(ECHO) "GEN $@"
732+
$(Q)$(PYTHON) $(FONT_CONVERT) $< 14 > $@
733+
734+
$(BUILD)/font_terminus_normal_16.c: $(PBTOP)/lib/pbio/src/image/fonts/terminus-normal.otb $(FONT_CONVERT)
735+
$(ECHO) "GEN $@"
736+
$(Q)$(PYTHON) $(FONT_CONVERT) $< 16 > $@
737+
738+
$(BUILD)/font_mono_8x5_8.c: $(PBTOP)/lib/pbio/src/image/fonts/mono_8x5.png $(FONT_CONVERT)
739+
$(ECHO) "GEN $@"
740+
$(Q)$(PYTHON) $(FONT_CONVERT) --image $< 8 > $@
643741

644742
$(BUILD)/hmi_ev3_ui_credits.c: $(CREDITS_CONVERT)
645743
$(ECHO) "Generating EV3 credits file"
@@ -710,4 +808,6 @@ deploy-openocd: $(BUILD)/firmware-base.bin
710808
$(ECHO) "Writing $< to the board via ST-LINK using OpenOCD"
711809
$(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $< $(TEXT0_ADDR)"
712810

811+
.DELETE_ON_ERROR:
812+
713813
include $(TOP)/py/mkrules.mk

bricks/_common/micropython.c

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -290,22 +290,31 @@ static void run_user_program(void) {
290290

291291
pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program) {
292292

293-
// For builtin programs, check requested ID against feature flags.
294-
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
295-
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_REPL) {
296-
return PBIO_SUCCESS;
297-
}
298-
#endif
299-
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_PORT_VIEW
300-
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW) {
301-
return PBIO_SUCCESS;
302-
}
303-
#endif
304-
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_IMU_CALIBRATION
305-
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION) {
306-
return PBIO_SUCCESS;
293+
// If requesting beyond a user slot, require that it is an available builtin.
294+
if (program->id > (PBSYS_CONFIG_HMI_NUM_SLOTS ? PBSYS_CONFIG_HMI_NUM_SLOTS - 1 : 0)) {
295+
switch (program->id) {
296+
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
297+
case PBIO_PYBRICKS_USER_PROGRAM_ID_REPL:
298+
return PBIO_SUCCESS;
299+
#endif
300+
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_PORT_VIEW
301+
case PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW:
302+
return PBIO_SUCCESS;
303+
#endif
304+
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_IMU_CALIBRATION
305+
case PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION:
306+
return PBIO_SUCCESS;
307+
#endif
308+
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_EV3_APPS
309+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_BUTTON_CONTROL:
310+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_IR_CONTROL:
311+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_PORT_VIEW:
312+
return PBIO_SUCCESS;
313+
#endif
314+
default:
315+
return PBIO_ERROR_NOT_SUPPORTED;
316+
}
307317
}
308-
#endif
309318

310319
// If requesting a user program, ensure that it exists and is valid.
311320
uint32_t program_size = program->code_end - program->code_start;
@@ -392,6 +401,21 @@ void pbsys_main_run_program(pbsys_main_program_t *program) {
392401
break;
393402
#endif
394403

404+
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_EV3_APPS
405+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_BUTTON_CONTROL:
406+
pb_package_pybricks_init(false);
407+
pyexec_frozen_module("_ev3_motor_button_control.py", false);
408+
break;
409+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_MOTOR_IR_CONTROL:
410+
pb_package_pybricks_init(false);
411+
pyexec_frozen_module("_ev3_motor_ir_control.py", false);
412+
break;
413+
case PBIO_PYBRICKS_USER_PROGRAM_ID_EV3_PORT_VIEW:
414+
pb_package_pybricks_init(false);
415+
pyexec_frozen_module("_ev3_port_view.py", false);
416+
break;
417+
#endif
418+
395419
default:
396420
// Init Pybricks package without auto-import.
397421
pb_package_pybricks_init(false);

bricks/_common/sources.mk

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
169169
drv/pwm/pwm_core.c \
170170
drv/pwm/pwm_ev3.c \
171171
drv/pwm/pwm_lp50xx_stm32.c \
172+
drv/pwm/pwm_pico.c \
172173
drv/pwm/pwm_stm32_tim.c \
173174
drv/pwm/pwm_test.c \
174175
drv/pwm/pwm_tlc5955_stm32.c \
@@ -214,9 +215,6 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
214215
src/drivebase.c \
215216
src/error.c \
216217
src/geometry.c \
217-
src/image/font_liberationsans_regular_14.c \
218-
src/image/font_terminus_normal_16.c \
219-
src/image/font_mono_8x5_8.c \
220218
src/image/image.c \
221219
src/imu.c \
222220
src/int_math.c \

bricks/ev3/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PBIO_PLATFORM = ev3
22
PB_MCU_FAMILY = TIAM1808
3-
3+
PB_FROZEN_MODULES = 1
44
PB_LIB_UMM_MALLOC = 1
55
PB_LIB_BTSTACK = 1
66
PB_MEDIA = 1
7+
PB_FONTS = 1
78

89
include ../_common/common.mk

bricks/ev3/manifest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
include("../_common/manifest.py")
2+
freeze_as_mpy("../ev3/modules", "_ev3_motor_button_control.py")
3+
freeze_as_mpy("../ev3/modules", "_ev3_motor_dc.py")
4+
freeze_as_mpy("../ev3/modules", "_ev3_motor_ir_control.py")
5+
freeze_as_mpy("../ev3/modules", "_ev3_port_view.py")
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from pybricks.tools import wait
2+
from pybricks.parameters import ImageFile, Button, Port, Color
3+
from pybricks.hubs import EV3Brick
4+
from pybricks.ev3devices import Motor
5+
6+
from _ev3_motor_dc import motor_set_dc
7+
8+
9+
# True means A&D pair is active. False means B&C pair is active.
10+
pair_ad_active = False
11+
12+
# Power used for all motors if active.
13+
POWER = 100
14+
15+
# Preload to avoid repeated allocation.
16+
IMG_POS = ImageFile._ROTATE_CW18
17+
IMG_NEG = ImageFile._ROTATE_CCW18
18+
IMG_AD = ImageFile._APP_MOTOR_CONTROL_AD
19+
IMG_BC = ImageFile._APP_MOTOR_CONTROL_BC
20+
21+
# UI is one of two prebuilt images from lms2012.
22+
ev3 = EV3Brick()
23+
24+
25+
def draw_ui():
26+
file = IMG_AD if pair_ad_active else IMG_BC
27+
ev3.screen.draw_image(0, 20, file)
28+
ev3.screen.draw_box(0, 0, 177, 16, fill=True, color=Color.WHITE)
29+
30+
31+
draw_ui()
32+
33+
while True:
34+
# Start with light on and motors off.
35+
draw_ui()
36+
ev3.light.on(Color.GREEN)
37+
for m in range(4):
38+
motor_set_dc(m, 0)
39+
40+
# Wait for anything to happen.
41+
while not (pressed := ev3.buttons.pressed()):
42+
wait(10)
43+
44+
# Center button toggles motor pair
45+
if Button.CENTER in pressed:
46+
pair_ad_active = not pair_ad_active
47+
draw_ui()
48+
while any(ev3.buttons.pressed()):
49+
wait(10)
50+
continue
51+
52+
# Determine motor power for horizontal buttons.
53+
dc_x = 0
54+
if Button.RIGHT in pressed:
55+
dc_x += POWER
56+
if Button.LEFT in pressed:
57+
dc_x -= POWER
58+
59+
# Determine motor power for vertical buttons.
60+
dc_y = 0
61+
if Button.UP in pressed:
62+
dc_y += POWER
63+
if Button.DOWN in pressed:
64+
dc_y -= POWER
65+
66+
# Activity heartbeat.
67+
if dc_x or dc_y:
68+
ev3.light.blink(Color.GREEN, [100, 100, 800, 100])
69+
else:
70+
ev3.light.on(Color.GREEN)
71+
72+
# Drive one or two motors.
73+
output = [0, 0, 0, 0]
74+
index_x = 3 if pair_ad_active else 2
75+
index_y = 0 if pair_ad_active else 1
76+
output[index_x] = motor_set_dc(index_x, dc_x)
77+
output[index_y] = motor_set_dc(index_y, dc_y)
78+
79+
# Draw output indicators if active.
80+
for m in range(len(output)):
81+
if output[m]:
82+
ev3.screen.draw_image(20 + m * 40, 2, IMG_POS if output[m] > 0 else IMG_NEG)
83+
84+
# Keep going until button state changes.
85+
while ev3.buttons.pressed() == pressed:
86+
wait(10)

0 commit comments

Comments
 (0)