Skip to content

Commit 1a1e79c

Browse files
Merge pull request #972 from cla7aye15I4nd/dev
Add "external device" module and LCD1602
2 parents 38564fd + 1180617 commit 1a1e79c

File tree

8 files changed

+356
-140
lines changed

8 files changed

+356
-140
lines changed

examples/mcu/stm32f411_i2c_lcd.py

Lines changed: 16 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,31 @@
11
import sys
2+
23
sys.path.append("../..")
34

45
from qiling.core import Qiling
56
from qiling.const import QL_VERBOSE
7+
from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602
68

7-
import pygame
8-
import threading
9-
10-
11-
class LCD:
12-
@classmethod
13-
def get_pattern(cls, ch):
14-
lo = (ch >> 0) & 0xf
15-
up = (ch >> 4) & 0xf
16-
with open('LCD1602A.txt') as f:
17-
lines = f.read().splitlines()[lo * 9 + 1: lo * 9 + 9]
18-
pattern = [line[up * 6 + 1: up * 6 + 6] for line in lines]
19-
20-
return pattern
21-
22-
@classmethod
23-
def make_screen(cls, infos):
24-
sc = []
25-
for info in infos:
26-
ps = [LCD.get_pattern(x) for x in info]
27-
ln = [''.join(p[r] for p in ps) for r in range(8)]
28-
sc += ln
29-
30-
return sc
31-
32-
class LCD1602(LCD):
33-
def __init__(self) -> None:
34-
super().__init__()
35-
36-
self.rows, self.cols = 2, 16
37-
self.cheight, self.cwidth = 8, 5
38-
39-
self.cur_row, self.cur_col = 0, 0
40-
41-
self.buf = []
42-
self.data = [[ord(' ') for _ in range(self.cols)] for _ in range(self.rows)]
43-
self.pixels = LCD.make_screen(self.data)
44-
45-
self.address = 0x3f << 1
46-
47-
def is_activate(self, i, j):
48-
return self.pixels[i][j] == '#'
49-
50-
def render(self):
51-
size = 10
52-
margin, interval = size * 4, size // 2
53-
54-
width = margin * 2 + size * (self.cols * self.cwidth) + interval * (self.cols - 1)
55-
height = margin * 2 + size * (self.rows * self.cheight) + interval * (self.rows - 1)
56-
57-
runable = True
58-
clock = pygame.time.Clock()
59-
win = pygame.display.set_mode((width, height))
60-
61-
pygame.display.set_caption("LCD 1602A")
629

63-
while runable:
64-
for event in pygame.event.get():
65-
if event.type == pygame.QUIT:
66-
runable = False
67-
68-
clock.tick(60)
69-
pygame.draw.rect(win, "#c9f6cd", ((size, size), (width - size*2, height - size*2)), border_radius=size)
70-
for i in range(self.rows * self.cheight):
71-
for j in range(self.cols * self.cwidth):
72-
x = margin + size * j + interval * (j // self.cwidth)
73-
y = margin + size * i + interval * (i // self.cheight)
10+
def create(path, lcd):
11+
ql = Qiling([path], archtype="cortex_m", profile="stm32f411", verbose=QL_VERBOSE.DEBUG)
7412

75-
color = "#446644" if self.is_activate(i, j) else "#bbeebb"
76-
pygame.draw.rect(win, color, ((x, y), (size-1, size-1)))
77-
78-
pygame.display.update()
79-
80-
print('LCD quit')
81-
pygame.quit()
82-
83-
def send(self, buf):
84-
for data in buf:
85-
self.buf.append(data)
86-
87-
if len(self.buf) == 4:
88-
up = self.buf[0] & 0xf0
89-
lo = self.buf[3] & 0xf0
90-
cmd = up | (lo >> 4)
91-
92-
if self.buf[0] & 0x1:
93-
if self.cur_col < 16 and self.cur_row < 2:
94-
self.data[self.cur_row][self.cur_col] = cmd
95-
self.cur_col += 1
96-
self.pixels = LCD.make_screen(self.data)
97-
98-
elif cmd == 0x1:
99-
self.data = [[ord(' ') for _ in range(self.cols)] for _ in range(self.rows)]
100-
self.pixels = LCD.make_screen(self.data)
101-
102-
elif up == 0x80:
103-
self.cur_row, self.cur_col = 0, lo >> 4
104-
105-
elif up == 0xc0:
106-
self.cur_row, self.cur_col = 1, lo >> 4
107-
108-
self.buf = []
109-
110-
def run(self):
111-
threading.Thread(target=self.render).start()
112-
113-
def make(path, lcd):
114-
ql = Qiling([path],
115-
archtype="cortex_m", profile="stm32f411", verbose=QL_VERBOSE.DEFAULT)
116-
117-
ql.hw.create('i2c1').connect(lcd)
13+
ql.hw.create('i2c1')
11814
ql.hw.create('rcc')
11915
ql.hw.create('gpioa')
120-
ql.hw.create('gpiob')
16+
ql.hw.create('gpiob')
17+
18+
ql.hw.i2c1.watch()
19+
ql.hw.i2c1.connect(lcd)
12120

21+
ql.hw.systick.set_ratio(100)
22+
12223
return ql
12324

12425
if __name__ == "__main__":
125-
lcd = LCD1602()
126-
lcd.run()
26+
lcd = PyGameLCD1602()
12727

128-
make("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=700000)
129-
make("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=2000000)
28+
create("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=50000)
29+
create("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=100000)
30+
31+
lcd.quit()

qiling/hw/connectivity.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@
1111
from qiling.hw.peripheral import QlPeripheral
1212

1313

14+
class PeripheralTube(queue.Queue):
15+
def __init__(self):
16+
super().__init__()
17+
18+
def readable(self) -> bool:
19+
return not self.empty()
20+
21+
def read(self, numb:int = 4096) -> bytes:
22+
data = bytearray()
23+
for _ in range(numb):
24+
if not self.readable():
25+
break
26+
data.append(self.get())
27+
28+
return bytes(data)
29+
30+
def write(self, data: bytes):
31+
for byte in bytearray(data):
32+
self.put(byte)
33+
34+
1435
class QlConnectivityPeripheral(QlPeripheral):
1536
class Type(ctypes.Structure):
1637
""" Define the reigister fields of peripheral.
@@ -31,64 +52,58 @@ class Type(ctypes.Structure):
3152
def __init__(self, ql: Qiling, label: str, limit:int = 1):
3253
super().__init__(ql, label)
3354

34-
self.rtube = queue.Queue()
35-
self.wtube = queue.Queue()
55+
self.itube = PeripheralTube()
56+
self.otube = PeripheralTube()
3657

3758
self.limit = limit
3859
self.device_list = []
3960

4061
def has_input(self):
41-
return not self.rtube.empty()
62+
return self.itube.readable()
4263

4364
def send(self, data: bytes):
4465
""" Send data into the peripheral.
4566
4667
Example:
4768
ql.hw.usart1.send(b'hello')
4869
"""
49-
50-
for byte in bytearray(data):
51-
self.rtube.put(byte)
70+
self.itube.write(data)
5271

5372
def recv(self, numb:int = 4096) -> bytes:
5473
""" Receive data from peripheral
5574
5675
Example:
57-
data = ql.hw.i2c1.send()
76+
data = ql.hw.i2c1.recv()
5877
"""
59-
data = bytearray()
60-
while self.can_recv() and numb != 0:
61-
data.append(self.wtube.get())
62-
numb -= 1
63-
64-
return bytes(data)
65-
66-
def can_recv(self):
67-
return not self.wtube.empty()
78+
return self.otube.read(numb)
6879

6980
def send_to_user(self, data: int):
7081
""" send single byte to user
71-
"""
72-
73-
self.wtube.put(data)
82+
"""
83+
self.otube.put(data)
7484

7585
def recv_from_user(self) -> bytes:
7686
""" Read single byte from user input
77-
"""
78-
79-
return self.rtube.get()
87+
"""
88+
return self.itube.get()
8089

8190
def connect(self, device):
8291
if len(self.device_list) < self.limit:
8392
self.device_list.append(device)
8493

8594
@staticmethod
8695
def device_handler(func):
96+
""" Send one byte to all devices
97+
"""
8798
def wrapper(self):
88-
if self.device_list and self.can_recv():
89-
data = self.recv(numb=1)
99+
if len(self.device_list) > 0:
100+
if self.otube.readable():
101+
data = self.recv(1)
102+
for device in self.device_list:
103+
device.send(data)
104+
90105
for device in self.device_list:
91-
device.send(data)
106+
device.step()
92107

93108
func(self)
94109

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#

0 commit comments

Comments
 (0)