Skip to content
This repository was archived by the owner on Dec 23, 2021. It is now read-only.

Commit 83aa71f

Browse files
committed
Merge branch 'users/t-xunguy/clue-sensors' of https://github.com/microsoft/vscode-python-devicesimulator into users/t-xunguy/clue-sensors
2 parents 1fb3349 + a08b688 commit 83aa71f

24 files changed

+737
-189
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ You will be prompted to install the Python dependencies during the first use.
4141

4242
### Features
4343

44-
- IntelliSense and syntax highlighting for CircuitPython code
44+
- IntelliSense and syntax highlighting for CircuitPython code for the CPX library
4545
- Template file generation
4646
- Integrated Python Debugging for the Simulator
4747
- Serial monitor (available on Windows and Mac only)
@@ -91,7 +91,7 @@ In Device Simulator Express, you can use keyboard to interact with the device:
9191
## BBC micro:bit Simulator
9292

9393
### Features
94-
- IntelliSense and syntax highlighting for micro:bit code
94+
- IntelliSense and syntax highlighting for MicroPython code for the micro:bit library
9595
- Template file generation
9696
- Integrated Python Debugging for the Simulator
9797
- Deploy MicroPython code to the physical device
Binary file not shown.

src/base_circuitpython/base_cp_constants.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
class CLUE_STATE:
2+
BUTTON_A = "button_a"
3+
BUTTON_B = "button_b"
4+
PRESSED_BUTTONS = "pressed_buttons"
5+
SEA_LEVEL_PRESSURE = "sea_level_pressure"
6+
TEMPERATURE = "temperature"
7+
PROXIMITY = "proximity"
8+
GESTURE = "gesture"
9+
HUMIDITY = "humidity"
10+
PRESSURE = "pressure"
11+
PIXEL = "pixel"
12+
# Accelerometer
13+
MOTION_X = "motion_x"
14+
MOTION_Y = "motion_y"
15+
MOTION_Z = "motion_z"
16+
# Light/color sensor
17+
LIGHT_R = "light_r"
18+
LIGHT_G = "light_g"
19+
LIGHT_B = "light_b"
20+
LIGHT_C = "light_c"
21+
# Magnetometer
22+
MAGNET_X = "magnet_x"
23+
MAGNET_Y = "magnet_y"
24+
MAGNET_Z = "magnet_z"
25+
# Gyroscope
26+
GYRO_X = "gyro_x"
27+
GYRO_Y = "gyro_y"
28+
GYRO_Z = "gyro_z"
29+
30+
131
CPX = "CPX"
232
CLUE = "CLUE"
333
PIXELS = "pixels"
@@ -9,12 +39,34 @@
939
IMG_DIR_NAME = "img"
1040
SCREEN_HEIGHT_WIDTH = 240
1141

12-
EXPECTED_INPUT_BUTTONS = set(["button_a", "button_b"])
42+
EXPECTED_INPUT_BUTTONS = set([CLUE_STATE.BUTTON_A, CLUE_STATE.BUTTON_B])
1343

14-
ALL_EXPECTED_INPUT_EVENTS = set(["temperature", "light_r", "light_g", "light_b", "light_c", "motion_x", "motion_y", "motion_z", "humidity", "pressure", "proximity"])
44+
ALL_EXPECTED_INPUT_EVENTS = set(
45+
[
46+
CLUE_STATE.TEMPERATURE,
47+
CLUE_STATE.LIGHT_R,
48+
CLUE_STATE.LIGHT_G,
49+
CLUE_STATE.LIGHT_B,
50+
CLUE_STATE.LIGHT_C,
51+
CLUE_STATE.MOTION_X,
52+
CLUE_STATE.MOTION_Y,
53+
CLUE_STATE.MOTION_Z,
54+
CLUE_STATE.HUMIDITY,
55+
CLUE_STATE.PRESSURE,
56+
CLUE_STATE.PROXIMITY,
57+
CLUE_STATE.GESTURE,
58+
]
59+
)
1560

1661
BMP_IMG = "BMP"
1762

1863
BMP_IMG_ENDING = ".bmp"
1964

20-
NO_VALID_IMGS_ERR = "No valid images"
65+
NO_VALID_IMGS_ERR = "No valid images"
66+
67+
BLINKA_BMP = "blinka.bmp"
68+
CLUE_TERMINAL_LINE_HEIGHT = 16
69+
CLUE_TERMINAL_LINE_NUM_MAX = 15
70+
CLUE_TERMINAL_X_OFFSET = 15
71+
CLUE_TERMINAL_Y_OFFSET = 5
72+
CLUE_TERMINAL_LINE_BREAK_AMT = 37

src/base_circuitpython/board.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,27 @@
22
# https://learn.adafruit.com/arduino-to-circuitpython/the-board-module
33

44

5+
import terminal_handler
6+
7+
58
class Display:
69
def __init__(self):
7-
pass
10+
self.active_group = None
11+
self.terminal = terminal_handler.Terminal()
12+
13+
def show(self, group=None):
14+
if group != self.active_group:
15+
self.active_group = group
16+
17+
if group == None:
18+
self.terminal.draw()
19+
return
820

9-
def show(self, group):
10-
group.draw()
21+
# if the group has no attribute called
22+
# "draw", then it is liable for updating itself
23+
# when it calls show
24+
if hasattr(group, "draw"):
25+
group.draw()
1126

1227

1328
DISPLAY = Display()

src/base_circuitpython/displayio/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
from .palette import Palette
1010

1111
# references to img and bmp_img are for testing purposes
12-
from .tile_grid import TileGrid, img, bmp_img
12+
from .tile_grid import TileGrid

src/base_circuitpython/displayio/group.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from PIL import Image
44
import adafruit_display_text
55

6-
from .tile_grid import TileGrid, bmp_img, img
6+
from .tile_grid import TileGrid
77
from . import constants as CONSTANTS
88

99
import common
10+
import board
1011

1112
# Group implementation loosely based on the
1213
# displayio.Group class in Adafruit CircuitPython
@@ -16,12 +17,17 @@
1617

1718

1819
class Group:
19-
def __init__(self, max_size, scale=1, auto_write=True):
20+
def __init__(self, max_size, scale=1, check_active_group_ref=True, auto_write=True):
21+
self.__check_active_group_ref = check_active_group_ref
22+
self.__auto_write = auto_write
2023
self.__contents = []
2124
self.max_size = max_size
2225
self.scale = scale
23-
self.auto_write = auto_write
24-
self.in_group = False
26+
self.parent = None
27+
28+
@property
29+
def in_group(self):
30+
return self.parent != None
2531

2632
def append(self, item):
2733
if len(self.__contents) == self.max_size:
@@ -32,19 +38,47 @@ def append(self, item):
3238
raise ValueError(CONSTANTS.LAYER_ALREADY_IN_GROUP)
3339

3440
self.__contents.append(item)
35-
item.in_group = True
36-
if self.auto_write:
37-
self.draw(show=True)
41+
item.parent = self
42+
43+
self.__elem_changed()
44+
45+
def __elem_changed(self):
46+
# Ensure that this group is what the board is currently showing.
47+
# Otherwise, don't bother to draw it.
48+
if (
49+
self.__auto_write
50+
and self.__check_active_group_ref
51+
and board.DISPLAY.active_group == self
52+
):
53+
self.draw()
54+
55+
elif self.in_group:
56+
57+
# If a sub-group is modified, propagate to top level to
58+
# see if one of the parents are the current active group.
59+
self.parent.__elem_changed()
3860

3961
def __getitem__(self, index):
4062
return self.__contents[index]
4163

4264
def __setitem__(self, index, val):
65+
old_val = self.__contents[index]
66+
4367
self.__contents[index] = val
4468

45-
def draw(self, x=0, y=0, scale=None, show=False):
69+
if old_val != val:
70+
self.__elem_changed()
71+
72+
def draw(self, img=None, x=0, y=0, scale=None, show=True):
4673
# this function is not a part of the orignal implementation
47-
# it is what prints itself and its children to the frontend
74+
# it is what draws itself and its children and potentially shows it to the
75+
# frontend
76+
if img == None:
77+
img = Image.new(
78+
"RGBA",
79+
(CONSTANTS.SCREEN_HEIGHT_WIDTH, CONSTANTS.SCREEN_HEIGHT_WIDTH),
80+
(0, 0, 0, 0),
81+
)
4882
if scale is None:
4983
scale = self.scale
5084
else:
@@ -55,11 +89,11 @@ def draw(self, x=0, y=0, scale=None, show=False):
5589
# adafruit_display_text has some positioning considerations
5690
# that need to be handled.
5791

58-
# found manually, display must be positioned upwards
92+
# This was found manually, display must be positioned upwards
5993
# 1 unit (1 unit * scale = scale)
6094
y -= scale
6195

62-
# group is positioned against anchored_position (default (0,0)),
96+
# Group is positioned against anchored_position (default (0,0)),
6397
# which is positioned against anchor_point
6498

6599
x += self._anchor_point[0]
@@ -72,15 +106,19 @@ def draw(self, x=0, y=0, scale=None, show=False):
72106

73107
for elem in self.__contents:
74108
if isinstance(elem, Group):
75-
elem.draw(x, y, scale, False)
109+
img = elem.draw(img=img, x=x, y=y, scale=scale, show=False,)
76110
else:
77-
elem.draw(x, y, scale)
111+
img = elem.draw(img=img, x=x, y=y, scale=scale)
78112

113+
# show should only be true to the highest parent group
79114
if show:
80-
self.show()
115+
self.show(img)
116+
117+
# return value only used if this is within another group
118+
return img
81119

82-
def show(self):
83-
# sends current bmp_img to the frontend
120+
def show(self, img):
121+
# sends current img to the frontend
84122
buffered = BytesIO()
85123
img.save(buffered, format="BMP")
86124
byte_base64 = base64.b64encode(buffered.getvalue())
@@ -96,4 +134,7 @@ def __len__(self):
96134
return len(self.__contents)
97135

98136
def pop(self, i=-1):
99-
return self.__contents.pop(i)
137+
item = self.__contents.pop(i)
138+
item.parent = None
139+
self.__elem_changed()
140+
return item

src/base_circuitpython/displayio/test/test_group.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from common import utils
99

10-
from ..tile_grid import TileGrid, img, bmp_img
10+
from ..tile_grid import TileGrid
1111
from ..group import Group
1212
from ..palette import Palette
1313
from ..bitmap import Bitmap
@@ -149,20 +149,22 @@ def test_draw_group(
149149
tg = TileGrid(bitmap=bmp_1, pixel_shader=palette, position=(0, 0))
150150
tg2 = TileGrid(bitmap=bmp_2, pixel_shader=palette, position=(50, 50))
151151

152-
group_main = Group(max_size=10, scale=scale_main)
152+
group_main = Group(max_size=10, scale=scale_main, check_active_group_ref=False)
153153
group_sub = Group(max_size=10, scale=scale_sub)
154154

155155
group_sub.append(tg)
156156
group_main.append(group_sub)
157157
group_main.append(tg2)
158+
# img = Image.new("RGBA", (240, 240))
159+
img = group_main.draw()
158160

159-
group_main.draw(0, 0)
161+
img.putalpha(255)
160162
expected = Image.open(
161163
os.path.join(self.abs_path, "img", "group_test_result.bmp")
162164
)
163165
expected.putalpha(255)
164166
bmp_img_expected = expected.load()
165-
167+
bmp_img = img.load()
166168
for i in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
167169
for j in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
168170
assert bmp_img_expected[j, i] == bmp_img[j, i]

src/base_circuitpython/displayio/test/test_tile_grid.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
2-
from ..tile_grid import TileGrid, img, bmp_img
2+
from PIL import Image
3+
from ..tile_grid import TileGrid
34
from ..palette import Palette
45
from ..bitmap import Bitmap
56
from .. import constants as CONSTANTS
@@ -135,9 +136,12 @@ def test_draw(
135136

136137
tg = TileGrid(bitmap=bmp, pixel_shader=palette, position=(0, 0))
137138
tg2 = TileGrid(bitmap=bmp, pixel_shader=palette, position=(0, 0))
138-
139+
img = Image.new(
140+
"RGBA", (CONSTANTS.SCREEN_HEIGHT_WIDTH, CONSTANTS.SCREEN_HEIGHT_WIDTH)
141+
)
139142
# without scaling, test output
140-
tg.draw(x_offset, y_offset, 1)
143+
img = tg.draw(img, x_offset, y_offset, 1)
144+
bmp_img = img.load()
141145
for i in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
142146
for j in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
143147
if (i in range(y_offset + y, y_offset + y + draw_h)) and (
@@ -149,8 +153,12 @@ def test_draw(
149153
):
150154
assert bmp_img[j, i] == bg_color
151155

156+
img = Image.new(
157+
"RGBA", (CONSTANTS.SCREEN_HEIGHT_WIDTH, CONSTANTS.SCREEN_HEIGHT_WIDTH)
158+
)
152159
# with scaling, test output
153-
tg.draw(x_offset, y_offset, scale)
160+
img = tg.draw(img, x_offset, y_offset, scale)
161+
bmp_img = img.load()
154162
for i in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
155163
for j in range(CONSTANTS.SCREEN_HEIGHT_WIDTH):
156164
if (

src/base_circuitpython/displayio/tile_grid.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,6 @@
1212
# https://circuitpython.readthedocs.io/en/5.0.x/shared-bindings/displayio/TileGrid.html
1313

1414

15-
# Create a new black (default) image
16-
img = Image.new(
17-
"RGBA", (CONSTANTS.SCREEN_HEIGHT_WIDTH, CONSTANTS.SCREEN_HEIGHT_WIDTH), (0, 0, 0, 0)
18-
)
19-
20-
# Create the pixel map
21-
# All displayio classes can access this
22-
# instance to read and write to the output image.
23-
bmp_img = img.load()
24-
25-
2615
class TileGrid:
2716
def __init__(
2817
self,
@@ -56,7 +45,11 @@ def __init__(
5645
self.bitmap = bitmap
5746
self.pixel_shader = pixel_shader
5847
self.default_tile = default_tile
59-
self.in_group = False
48+
self.parent = None
49+
50+
@property
51+
def in_group(self):
52+
return self.parent != None
6053

6154
# setitem for an index simply gets the index of the bitmap
6255
# rather than the tile index
@@ -78,8 +71,7 @@ def __getitem__(self, index):
7871

7972
# methods that are not in the origin class:
8073

81-
def draw(self, x, y, scale):
82-
74+
def draw(self, img, x, y, scale):
8375
# draw the current bitmap with
8476
# appropriate scale on the global bmp_img
8577
x = self.x * scale + x
@@ -90,6 +82,7 @@ def draw(self, x, y, scale):
9082
)
9183

9284
img.paste(new_shape, (x, y), new_shape)
85+
return img
9386

9487
def draw_group(self, x, y, y_start, y_end, x_start, x_end, scale):
9588
height = y_end - y_start

src/base_circuitpython/img/blinka.bmp

169 KB
Binary file not shown.

0 commit comments

Comments
 (0)