Skip to content

Commit f2ac71d

Browse files
Add draft_code
1 parent fdd42d8 commit f2ac71d

20 files changed

+2179
-0
lines changed
Binary file not shown.
Binary file not shown.

draft_code/apps.py_dont_compile_mpy_dontwork

Lines changed: 449 additions & 0 deletions
Large diffs are not rendered by default.

draft_code/asyncwebsocketclient.py

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
import socket
2+
import asyncio as a
3+
import binascii as b
4+
import random as r
5+
from collections import namedtuple
6+
import re
7+
import struct
8+
import ssl
9+
10+
# Opcodes
11+
OP_CONT = const(0x0)
12+
OP_TEXT = const(0x1)
13+
OP_BYTES = const(0x2)
14+
OP_CLOSE = const(0x8)
15+
OP_PING = const(0x9)
16+
OP_PONG = const(0xa)
17+
18+
# Close codes
19+
CLOSE_OK = const(1000)
20+
CLOSE_GOING_AWAY = const(1001)
21+
CLOSE_PROTOCOL_ERROR = const(1002)
22+
CLOSE_DATA_NOT_SUPPORTED = const(1003)
23+
CLOSE_BAD_DATA = const(1007)
24+
CLOSE_POLICY_VIOLATION = const(1008)
25+
CLOSE_TOO_BIG = const(1009)
26+
CLOSE_MISSING_EXTN = const(1010)
27+
CLOSE_BAD_CONDITION = const(1011)
28+
29+
URL_RE = re.compile(r'(wss|ws)://([A-Za-z0-9-\.]+)(?:\:([0-9]+))?(/.+)?')
30+
URI = namedtuple('URI', ('protocol', 'hostname', 'port', 'path'))
31+
32+
class AsyncWebsocketClient:
33+
def __init__(self, ms_delay_for_read: int = 5):
34+
self._open = False
35+
self.delay_read = ms_delay_for_read
36+
self._lock_for_open = a.Lock()
37+
self.sock = None
38+
39+
async def open(self, new_val: bool = None):
40+
await self._lock_for_open.acquire()
41+
if new_val is not None:
42+
if not new_val and self.sock:
43+
self.sock.close()
44+
self.sock = None
45+
self._open = new_val
46+
to_return = self._open
47+
self._lock_for_open.release()
48+
return to_return
49+
50+
async def close(self):
51+
return await self.open(False)
52+
53+
def urlparse(self, uri):
54+
"""Parse ws or wss:// URLs"""
55+
match = URL_RE.match(uri)
56+
if match:
57+
protocol, host, port, path = match.group(1), match.group(2), match.group(3), match.group(4)
58+
59+
if protocol not in ['ws', 'wss']:
60+
raise ValueError('Scheme {} is invalid'.format(protocol))
61+
62+
if port is None:
63+
port = (80, 443)[protocol == 'wss']
64+
65+
return URI(protocol, host, int(port), path)
66+
67+
async def a_readline(self):
68+
line = None
69+
while line is None:
70+
line = self.sock.readline()
71+
await a.sleep_ms(self.delay_read)
72+
73+
return line
74+
75+
async def a_read(self, size: int = None):
76+
if size == 0:
77+
return b''
78+
chunks = []
79+
80+
while True:
81+
b = self.sock.read(size)
82+
await a.sleep_ms(self.delay_read)
83+
84+
# Continue reading if the socket returns None
85+
if b is None: continue
86+
87+
# In some cases, the socket will return an empty bytes
88+
# after PING or PONG frames, we need to ignore them.
89+
if len(b) == 0: break
90+
91+
chunks.append(b)
92+
size -= len(b)
93+
94+
# After reading the first chunk, we can break if size is None or 0
95+
if size is None or size == 0: break
96+
97+
# Join all the chunks and return them
98+
return b''.join(chunks)
99+
100+
async def handshake(self, uri, headers=[], keyfile=None, certfile=None, cafile=None, cert_reqs=0):
101+
if self.sock:
102+
self.close()
103+
104+
self.sock = socket.socket()
105+
self.uri = self.urlparse(uri)
106+
ai = socket.getaddrinfo(self.uri.hostname, self.uri.port)
107+
addr = ai[0][4]
108+
109+
self.sock.connect(addr)
110+
self.sock.setblocking(False)
111+
112+
if self.uri.protocol == 'wss':
113+
cadata = None
114+
if not cafile is None:
115+
with open(cafile, 'rb') as f:
116+
cadata = f.read()
117+
self.sock = ssl.wrap_socket(
118+
self.sock, server_side=False,
119+
key=keyfile, cert=certfile,
120+
cert_reqs=cert_reqs, # 0 - NONE, 1 - OPTIONAL, 2 - REQUIED
121+
cadata=cadata,
122+
server_hostname=self.uri.hostname
123+
)
124+
125+
def send_header(header, *args):
126+
self.sock.write(header % args + '\r\n')
127+
128+
# Sec-WebSocket-Key is 16 bytes of random base64 encoded
129+
key = b.b2a_base64(bytes(r.getrandbits(8)
130+
for _ in range(16)))[:-1]
131+
132+
send_header(b'GET %s HTTP/1.1', self.uri.path or '/')
133+
send_header(b'Host: %s:%s', self.uri.hostname, self.uri.port)
134+
send_header(b'Connection: Upgrade')
135+
send_header(b'Upgrade: websocket')
136+
send_header(b'Sec-WebSocket-Key: %s', key)
137+
send_header(b'Sec-WebSocket-Version: 13')
138+
send_header(b'Origin: http://{hostname}:{port}'.format(
139+
hostname=self.uri.hostname,
140+
port=self.uri.port)
141+
)
142+
143+
for key, value in headers:
144+
send_header(b'%s: %s', key, value)
145+
146+
send_header(b'')
147+
148+
line = await self.a_readline()
149+
header = (line)[:-2]
150+
if not header.startswith(b'HTTP/1.1 101 '):
151+
raise Exception(header)
152+
153+
# We don't (currently) need these headers
154+
# FIXME: should we check the return key?
155+
while header:
156+
line = await self.a_readline()
157+
header = (line)[:-2]
158+
159+
return await self.open(True)
160+
161+
async def read_frame(self, max_size=None):
162+
# Frame header
163+
byte1, byte2 = struct.unpack('!BB', await self.a_read(2))
164+
165+
# Byte 1: FIN(1) _(1) _(1) _(1) OPCODE(4)
166+
fin = bool(byte1 & 0x80)
167+
opcode = byte1 & 0x0f
168+
169+
# Byte 2: MASK(1) LENGTH(7)
170+
mask = bool(byte2 & (1 << 7))
171+
length = byte2 & 0x7f
172+
173+
if length == 126: # Magic number, length header is 2 bytes
174+
length, = struct.unpack('!H', await self.a_read(2))
175+
elif length == 127: # Magic number, length header is 8 bytes
176+
length, = struct.unpack('!Q', await self.a_read(8))
177+
178+
if mask: # Mask is 4 bytes
179+
mask_bits = await self.a_read(4)
180+
181+
try:
182+
data = await self.a_read(length)
183+
except MemoryError:
184+
# We can't receive this many bytes, close the socket
185+
self.close(code=CLOSE_TOO_BIG)
186+
# await self._stream.drain()
187+
return True, OP_CLOSE, None
188+
189+
if mask:
190+
data = bytes(b ^ mask_bits[i % 4]
191+
for i, b in enumerate(data))
192+
193+
return fin, opcode, data
194+
195+
def write_frame(self, opcode, data=b''):
196+
fin = True
197+
mask = True # messages sent by client are masked
198+
199+
length = len(data)
200+
201+
# Frame header
202+
# Byte 1: FIN(1) _(1) _(1) _(1) OPCODE(4)
203+
byte1 = 0x80 if fin else 0
204+
byte1 |= opcode
205+
206+
# Byte 2: MASK(1) LENGTH(7)
207+
byte2 = 0x80 if mask else 0
208+
209+
if length < 126: # 126 is magic value to use 2-byte length header
210+
byte2 |= length
211+
self.sock.write(struct.pack('!BB', byte1, byte2))
212+
213+
elif length < (1 << 16): # Length fits in 2-bytes
214+
byte2 |= 126 # Magic code
215+
self.sock.write(struct.pack('!BBH', byte1, byte2, length))
216+
217+
elif length < (1 << 64):
218+
byte2 |= 127 # Magic code
219+
self.sock.write(struct.pack('!BBQ', byte1, byte2, length))
220+
221+
else:
222+
raise ValueError()
223+
224+
if mask: # Mask is 4 bytes
225+
mask_bits = struct.pack('!I', r.getrandbits(32))
226+
self.sock.write(mask_bits)
227+
data = bytes(b ^ mask_bits[i % 4]
228+
for i, b in enumerate(data))
229+
230+
self.sock.write(data)
231+
232+
async def recv(self):
233+
while await self.open():
234+
try:
235+
fin, opcode, data = await self.read_frame()
236+
# except (ValueError, EOFError) as ex:
237+
except Exception as ex:
238+
print('Exception in recv while reading frame:', ex)
239+
await self.open(False)
240+
return
241+
242+
if not fin:
243+
raise NotImplementedError()
244+
245+
if opcode == OP_TEXT:
246+
return data.decode('utf-8')
247+
elif opcode == OP_BYTES:
248+
return data
249+
elif opcode == OP_CLOSE:
250+
await self.open(False)
251+
return
252+
elif opcode == OP_PONG:
253+
# Ignore this frame, keep waiting for a data frame
254+
continue
255+
elif opcode == OP_PING:
256+
try:
257+
# We need to send a pong frame
258+
self.write_frame(OP_PONG, data)
259+
260+
# And then continue to wait for a data frame
261+
continue
262+
except Exception as ex:
263+
print('Error sending pong frame:', ex)
264+
# If sending the pong frame fails, close the connection
265+
await self.open(False)
266+
return
267+
elif opcode == OP_CONT:
268+
# This is a continuation of a previous frame
269+
raise NotImplementedError(opcode)
270+
else:
271+
raise ValueError(opcode)
272+
273+
async def send(self, buf):
274+
if not await self.open():
275+
return
276+
if isinstance(buf, str):
277+
opcode = OP_TEXT
278+
buf = buf.encode('utf-8')
279+
elif isinstance(buf, bytes):
280+
opcode = OP_BYTES
281+
else:
282+
raise TypeError()
283+
self.write_frame(opcode, buf)
284+

draft_code/dropdown_switch.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Create a dropdown
2+
dropdown = lv.dropdown(lv.screen_active())
3+
dropdown.set_options("Option 1\nOption 2\nOption 3")
4+
dropdown.align(lv.ALIGN.CENTER, 0, 0)
5+
6+
7+
switch = lv.switch(lv.screen_active())
8+
switch.center()
9+

draft_code/image_decoder.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
3+
import lvgl as lv
4+
5+
def list_image_decoders():
6+
# Initialize LVGL
7+
lv.init()
8+
9+
# Start with the first decoder
10+
first = lv.image_decoder_t()
11+
#decoder = lv.image.decoder_get_next(first)
12+
decoder = lv.image_decoder_t.get_next(first)
13+
index = 0
14+
15+
# Iterate through all decoders
16+
while decoder is not None:
17+
print(f"Image Decoder {index}: {decoder}")
18+
index += 1
19+
#decoder = lv.image.decoder_get_next(decoder)
20+
decoder = lv.image_decoder_t.get_next(decoder)
21+
22+
if index == 0:
23+
print("No image decoders found.")
24+
else:
25+
print(f"Total image decoders: {index}")
26+
27+
# Run the function
28+
list_image_decoders()
29+
30+
31+
i = lv.image(lv.screen_active());
32+
#i.set_src("P:/home/user/sources/MicroPythonOS/artwork/image.jpg");
33+
i.set_src("P:/home/user/sources/MicroPythonOS/artwork/icon_64x64.jpg");
34+
i.center()
35+
h = lv.image_header_t()
36+
i.decoder_get_info(i.image_dsc, h)
37+
print("image info:")
38+
print(h)
39+
print(f"widthxheight: {h.w}x{h.h}")

0 commit comments

Comments
 (0)