Skip to content

Commit e5f6baf

Browse files
camtest: rework
1 parent 9b0057e commit e5f6baf

File tree

1 file changed

+118
-120
lines changed
  • internal_filesystem/apps/com.example.camtest/assets

1 file changed

+118
-120
lines changed

internal_filesystem/apps/com.example.camtest/assets/camtest.py

Lines changed: 118 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,12 @@
99

1010
# Variable to hold the current memoryview to prevent garbage collection
1111
current_cam_buffer = None
12+
image_dsc = None
13+
image = None
14+
qr_label = None
1215

1316

14-
cont = lv.obj(appscreen)
15-
cont.set_style_pad_all(0, 0)
16-
cont.set_style_border_width(0, 0)
17-
cont.set_size(lv.pct(100), lv.pct(100))
18-
cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
19-
20-
snap_button = lv.button(cont)
21-
snap_button.set_size(60, 60)
22-
snap_button.align(lv.ALIGN.RIGHT_MID, 0, 0)
23-
snap_label = lv.label(snap_button)
24-
snap_label.set_text(lv.SYMBOL.OK)
25-
snap_label.center()
26-
27-
def snap_button_click(e):
28-
print("Picture taken!")
29-
try:
30-
import os
31-
os.mkdir("data")
32-
os.mkdir("data/com.example.camtest")
33-
except OSError:
34-
pass
35-
if current_cam_buffer is not None:
36-
filename="data/com.example.camtest/capture.raw"
37-
try:
38-
with open(filename, 'wb') as f:
39-
f.write(current_cam_buffer)
40-
print(f"Successfully wrote current_cam_buffer to {filename}")
41-
except OSError as e:
42-
print(f"Error writing to file: {e}")
43-
44-
snap_button.add_event_cb(snap_button_click,lv.EVENT.CLICKED,None)
45-
46-
47-
qr_button = lv.button(cont)
48-
qr_button.set_size(60, 60)
49-
qr_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0)
50-
qr_label = lv.label(qr_button)
51-
qr_label.set_text(lv.SYMBOL.EYE_OPEN)
52-
qr_label.center()
53-
54-
def process_qr_buffer(buffer):
17+
def print_qr_buffer(buffer):
5518
try:
5619
# Try to decode buffer as a UTF-8 string
5720
result = buffer.decode('utf-8')
@@ -64,21 +27,52 @@ def process_qr_buffer(buffer):
6427
hex_str = ' '.join([f'{b:02x}' for b in buffer])
6528
return hex_str.lower()
6629

30+
# Byte-Order-Mark is added sometimes
31+
def remove_bom(buffer):
32+
bom = b'\xEF\xBB\xBF'
33+
if buffer.startswith(bom):
34+
return buffer[3:]
35+
return buffer
36+
6737
def qrdecode_live():
6838
# Image dimensions
6939
buffer_size = width * height # 240 * 240 = 57600 bytes
7040
while keepgoing and keepliveqrdecoding:
7141
try:
7242
import qrdecode
7343
result = qrdecode.qrdecode(current_cam_buffer, width, height)
74-
if result.startswith('\ufeff'): # Remove BOM (\ufeff) from the start of the decoded string, if present
75-
result = result[1:]
76-
result = process_qr_buffer(result)
44+
result = remove_bom(result)
45+
result = print_qr_buffer(result)
7746
print(f"QR decoding found: {result}")
7847
except Exception as e:
7948
print("QR decode error: ", e)
8049
time.sleep_ms(500)
8150

51+
52+
def close_button_click(e):
53+
global keepgoing
54+
print("Close button clicked")
55+
keepgoing = False
56+
57+
58+
def snap_button_click(e):
59+
print("Picture taken!")
60+
try:
61+
import os
62+
os.mkdir("data")
63+
os.mkdir("data/com.example.camtest")
64+
except OSError:
65+
pass
66+
if current_cam_buffer is not None:
67+
filename="data/com.example.camtest/capture.raw"
68+
try:
69+
with open(filename, 'wb') as f:
70+
f.write(current_cam_buffer)
71+
print(f"Successfully wrote current_cam_buffer to {filename}")
72+
except OSError as e:
73+
print(f"Error writing to file: {e}")
74+
75+
8276
def qr_button_click(e):
8377
global keepliveqrdecoding, qr_label
8478
if not keepliveqrdecoding:
@@ -96,26 +90,80 @@ def qr_button_click(e):
9690
keepliveqrdecoding = False
9791
qr_label.set_text(lv.SYMBOL.EYE_OPEN)
9892

99-
qr_button.add_event_cb(qr_button_click,lv.EVENT.CLICKED,None)
10093

94+
def try_capture():
95+
global current_cam_buffer, image_dsc, image
96+
if cam.frame_available():
97+
# Get new memoryview from camera
98+
new_cam_buffer = cam.capture() # Returns memoryview
99+
# Verify buffer size
100+
#if len(new_cam_buffer) != width * height * 2:
101+
# print("Invalid buffer size:", len(new_cam_buffer))
102+
# cam.free_buffer()
103+
# return
104+
# Update image descriptor with new memoryview
105+
image_dsc.data = new_cam_buffer
106+
# Set image source to update LVGL (implicitly invalidates widget)
107+
image.set_src(image_dsc)
108+
#image.invalidate() #does not work
109+
# Free the previous buffer (if any) after setting new data
110+
if current_cam_buffer is not None:
111+
cam.free_buffer() # Free the old buffer
112+
current_cam_buffer = new_cam_buffer # Store new buffer reference
101113

102-
close_button = lv.button(cont)
103-
close_button.set_size(60,60)
104-
close_button.align(lv.ALIGN.TOP_RIGHT, 0, 0)
105-
close_label = lv.label(close_button)
106-
close_label.set_text(lv.SYMBOL.CLOSE)
107-
close_label.center()
108-
def close_button_click(e):
109-
global keepgoing
110-
print("Close button clicked")
111-
keepgoing = False
112114

113-
close_button.add_event_cb(close_button_click,lv.EVENT.CLICKED,None)
114115

116+
def build_ui():
117+
global image, image_dsc,qr_label
118+
cont = lv.obj(appscreen)
119+
cont.set_style_pad_all(0, 0)
120+
cont.set_style_border_width(0, 0)
121+
cont.set_size(lv.pct(100), lv.pct(100))
122+
cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
123+
close_button = lv.button(cont)
124+
close_button.set_size(60,60)
125+
close_button.align(lv.ALIGN.TOP_RIGHT, 0, 0)
126+
close_label = lv.label(close_button)
127+
close_label.set_text(lv.SYMBOL.CLOSE)
128+
close_label.center()
129+
close_button.add_event_cb(close_button_click,lv.EVENT.CLICKED,None)
130+
snap_button = lv.button(cont)
131+
snap_button.set_size(60, 60)
132+
snap_button.align(lv.ALIGN.RIGHT_MID, 0, 0)
133+
snap_label = lv.label(snap_button)
134+
snap_label.set_text(lv.SYMBOL.OK)
135+
snap_label.center()
136+
snap_button.add_event_cb(snap_button_click,lv.EVENT.CLICKED,None)
137+
qr_button = lv.button(cont)
138+
qr_button.set_size(60, 60)
139+
qr_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0)
140+
qr_label = lv.label(qr_button)
141+
qr_label.set_text(lv.SYMBOL.EYE_OPEN)
142+
qr_label.center()
143+
qr_button.add_event_cb(qr_button_click,lv.EVENT.CLICKED,None)
144+
# Initialize LVGL image widget
145+
image = lv.image(cont)
146+
image.align(lv.ALIGN.LEFT_MID, 0, 0)
147+
image.set_rotation(900)
148+
# Create image descriptor once
149+
image_dsc = lv.image_dsc_t({
150+
"header": {
151+
"magic": lv.IMAGE_HEADER_MAGIC,
152+
"w": width,
153+
"h": height,
154+
"stride": width ,
155+
#"cf": lv.COLOR_FORMAT.RGB565
156+
"cf": lv.COLOR_FORMAT.L8
157+
},
158+
'data_size': width * height,
159+
'data': None # Will be updated per frame
160+
})
161+
image.set_src(image_dsc)
115162

116-
from camera import Camera, GrabMode, PixelFormat, FrameSize, GainCeiling
117163

118164
try:
165+
# time.sleep(1) doesn't help
166+
from camera import Camera, GrabMode, PixelFormat, FrameSize, GainCeiling
119167
cam = Camera(
120168
data_pins=[12,13,15,11,14,10,7,2],
121169
vsync_pin=6,
@@ -133,69 +181,19 @@ def close_button_click(e):
133181
grab_mode=GrabMode.LATEST
134182
)
135183
#cam.init() automatically done when creating the Camera()
184+
#cam.reconfigure(frame_size=FrameSize.HVGA)
185+
#frame_size=FrameSize.HVGA, # 480x320
186+
#frame_size=FrameSize.QVGA, # 320x240
187+
#frame_size=FrameSize.QQVGA # 160x120
188+
cam.set_vflip(True)
189+
build_ui()
190+
while appscreen == lv.screen_active() and keepgoing is True:
191+
try_capture()
192+
time.sleep_ms(100) # Allow for the MicroPython REPL to still work. Reducing it doesn't seem to affect the on-display FPS.
193+
print("App backgrounded, deinitializing camera...")
194+
cam.deinit()
195+
show_launcher()
136196
except Exception as e:
137-
print(f"Exception while initializing camera: {e}")
138-
139-
#cam.reconfigure(frame_size=FrameSize.HVGA)
140-
#frame_size=FrameSize.HVGA, # 480x320
141-
#frame_size=FrameSize.QVGA, # 320x240
142-
#frame_size=FrameSize.QQVGA # 160x120
143-
144-
cam.set_vflip(True)
145-
146-
147-
# Initialize LVGL image widget
148-
image = lv.image(cont)
149-
image.align(lv.ALIGN.LEFT_MID, 0, 0)
150-
image.set_rotation(900)
151-
152-
# Create image descriptor once
153-
image_dsc = lv.image_dsc_t({
154-
"header": {
155-
"magic": lv.IMAGE_HEADER_MAGIC,
156-
"w": width,
157-
"h": height,
158-
"stride": width ,
159-
#"cf": lv.COLOR_FORMAT.RGB565
160-
"cf": lv.COLOR_FORMAT.L8
161-
},
162-
'data_size': width * height,
163-
'data': None # Will be updated per frame
164-
})
165-
166-
# Set initial image source (optional, can be set in try_capture)
167-
image.set_src(image_dsc)
168-
169-
170-
def try_capture():
171-
global current_cam_buffer
172-
if cam.frame_available():
173-
# Get new memoryview from camera
174-
new_cam_buffer = cam.capture() # Returns memoryview
175-
# Verify buffer size
176-
#if len(new_cam_buffer) != width * height * 2:
177-
# print("Invalid buffer size:", len(new_cam_buffer))
178-
# cam.free_buffer()
179-
# return
180-
# Update image descriptor with new memoryview
181-
image_dsc.data = new_cam_buffer
182-
# Set image source to update LVGL (implicitly invalidates widget)
183-
image.set_src(image_dsc)
184-
#image.invalidate() #does not work
185-
# Free the previous buffer (if any) after setting new data
186-
if current_cam_buffer is not None:
187-
cam.free_buffer() # Free the old buffer
188-
current_cam_buffer = new_cam_buffer # Store new buffer reference
189-
190-
# Initial capture
191-
try_capture()
192-
193-
194-
while appscreen == lv.screen_active() and keepgoing is True:
195-
try_capture()
196-
time.sleep_ms(100) # Allow for the MicroPython REPL to still work. Reducing it doesn't seem to affect the on-display FPS.
197+
print(f"Exception: {e}")
197198

198-
print("App backgrounded, deinitializing camera...")
199-
cam.deinit()
200199

201-
show_launcher()

0 commit comments

Comments
 (0)