Skip to content

Commit 90bbac3

Browse files
authored
Add files via upload
1 parent c6fc6a2 commit 90bbac3

File tree

2 files changed

+345
-0
lines changed

2 files changed

+345
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#include <Wire.h>
2+
#include <Adafruit_GFX.h>
3+
#include <Adafruit_SSD1306.h>
4+
#include <SPI.h>
5+
#include <Bitcraze_PMW3901.h>
6+
7+
// OLED Display setup
8+
#define SCREEN_WIDTH 128
9+
#define SCREEN_HEIGHT 64
10+
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
11+
12+
// PMW3901 Sensor setup
13+
#define CS_PIN 5 // Chip Select Pin for PMW3901
14+
Bitcraze_PMW3901 flow(CS_PIN);
15+
16+
const unsigned char Start_icon [] PROGMEM = {
17+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
18+
0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f,
19+
0xe0, 0x07, 0xfc, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x3f, 0x80,
20+
0x03, 0xf8, 0x00, 0x00, 0x1f, 0xc0, 0x03, 0xf0, 0x00, 0x00, 0x0f, 0xc0, 0x07, 0xe0, 0x00, 0x00,
21+
0x07, 0xe0, 0x0f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0x0f, 0x80, 0x38, 0x00, 0x01, 0xf0, 0x1f, 0x00,
22+
0xfc, 0x00, 0x00, 0xf8, 0x1f, 0x01, 0xff, 0x00, 0x00, 0x78, 0x3e, 0x01, 0xff, 0x80, 0x00, 0x7c,
23+
0x3c, 0x01, 0xff, 0xe0, 0x00, 0x3c, 0x3c, 0x01, 0xef, 0xf0, 0x00, 0x3e, 0x7c, 0x01, 0xe3, 0xfc,
24+
0x00, 0x3e, 0x78, 0x01, 0xe1, 0xfe, 0x00, 0x3e, 0x78, 0x01, 0xe0, 0x7f, 0x80, 0x1e, 0x78, 0x01,
25+
0xe0, 0x3f, 0xc0, 0x1e, 0x78, 0x01, 0xe0, 0x0f, 0xc0, 0x1e, 0x78, 0x01, 0xe0, 0x07, 0xc0, 0x1e,
26+
0x78, 0x01, 0xe0, 0x07, 0xc0, 0x1e, 0x78, 0x01, 0xe0, 0x0f, 0xc0, 0x1e, 0x78, 0x01, 0xe0, 0x3f,
27+
0xc0, 0x1e, 0x78, 0x01, 0xe0, 0x7f, 0x80, 0x1e, 0x7c, 0x01, 0xe1, 0xfe, 0x00, 0x3e, 0x7c, 0x01,
28+
0xe3, 0xfc, 0x00, 0x3e, 0x3c, 0x01, 0xef, 0xf0, 0x00, 0x3e, 0x3c, 0x01, 0xff, 0xe0, 0x00, 0x3c,
29+
0x3e, 0x01, 0xff, 0x80, 0x00, 0x7c, 0x1f, 0x01, 0xff, 0x00, 0x00, 0x78, 0x1f, 0x00, 0xfc, 0x00,
30+
0x00, 0xf8, 0x0f, 0x80, 0x30, 0x00, 0x01, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0x07, 0xe0,
31+
0x00, 0x00, 0x07, 0xe0, 0x03, 0xf0, 0x00, 0x00, 0x0f, 0xc0, 0x01, 0xf8, 0x00, 0x00, 0x1f, 0x80,
32+
0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x3f, 0xf0, 0x0f,
33+
0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01,
34+
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
35+
};
36+
37+
const unsigned char LEFT_arrow [] PROGMEM = {
38+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
41+
0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00,
42+
0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f,
43+
0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00,
44+
0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff,
45+
0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff,
46+
0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
48+
0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff,
49+
0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00,
50+
0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00,
51+
0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07,
52+
0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00,
53+
0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56+
};
57+
58+
const unsigned char UP_arrow [] PROGMEM = {
59+
0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0,
60+
0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00,
61+
0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
62+
0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff,
63+
0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f,
64+
0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
65+
0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xfc,
66+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
67+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
68+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
69+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
70+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
71+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
72+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
73+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
74+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
75+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
76+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00
77+
};
78+
79+
const unsigned char RIGHT_arrow [] PROGMEM = {
80+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
83+
0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03,
84+
0xe0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00,
85+
0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x80,
86+
0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff,
87+
0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff,
88+
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
90+
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff,
91+
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x80,
92+
0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03,
93+
0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00,
94+
0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00,
95+
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
98+
};
99+
100+
const unsigned char DOWN_arrow [] PROGMEM = {
101+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
102+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
103+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
104+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
105+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
106+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
107+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
108+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
109+
0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00,
110+
0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc,
111+
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00,
112+
0x3f, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80,
113+
0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff,
114+
0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x07,
115+
0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00,
116+
0x00, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe,
117+
0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00,
118+
0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00
119+
};
120+
121+
122+
123+
// Arrow width & height
124+
#define ARROW_WIDTH 48
125+
#define ARROW_HEIGHT 48
126+
127+
// Store last movement direction
128+
String lastMovement = "No Movement";
129+
const unsigned char* lastArrow = nullptr;
130+
131+
void updateDisplay() {
132+
display.clearDisplay();
133+
// Center the arrow
134+
int x = (SCREEN_WIDTH - ARROW_WIDTH) / 2;
135+
int y = (SCREEN_HEIGHT - ARROW_HEIGHT) / 2;
136+
137+
if (lastArrow) {
138+
display.drawBitmap(40, 8, lastArrow, ARROW_WIDTH, ARROW_HEIGHT, WHITE);
139+
}
140+
display.display();
141+
}
142+
143+
void setup() {
144+
Serial.begin(115200);
145+
146+
// Initialize OLED
147+
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
148+
Serial.println("SSD1306 allocation failed");
149+
while (1);
150+
}
151+
152+
// Initialize PMW3901
153+
SPI.begin();
154+
if (!flow.begin()) {
155+
Serial.println("PMW3901 Initialization failed!");
156+
display.clearDisplay();
157+
display.setTextColor(WHITE);
158+
display.setCursor(10, 25);
159+
display.println("Sensor Fail!");
160+
display.display();
161+
while (1);
162+
}
163+
164+
Serial.println("PMW3901 Initialized");
165+
display.clearDisplay();
166+
lastArrow = Start_icon;
167+
updateDisplay();
168+
}
169+
170+
void loop() {
171+
int16_t deltaX = 0, deltaY = 0;
172+
173+
// Read motion data
174+
flow.readMotionCount(&deltaX, &deltaY); // Directly updates deltaX & deltaY
175+
176+
Serial.print("DX: "); Serial.print(deltaX);
177+
Serial.print(" DY: "); Serial.println(deltaY);
178+
179+
// Ignore small movements
180+
if (abs(deltaX) < 3 && abs(deltaY) < 3) {
181+
return; // Do not update display if no new movement
182+
}
183+
184+
// Detect only Up, Down, Left, Right
185+
if (deltaX > 3 && abs(deltaY) < 3) {
186+
lastMovement = "Right";
187+
lastArrow = RIGHT_arrow;
188+
} else if (deltaX < -3 && abs(deltaY) < 3) {
189+
lastMovement = "Left";
190+
lastArrow = LEFT_arrow;
191+
} else if (deltaY > 3 && abs(deltaX) < 3) {
192+
lastMovement = "UP";
193+
lastArrow = UP_arrow;
194+
} else if (deltaY < -3 && abs(deltaX) < 3) {
195+
lastMovement = "Down";
196+
lastArrow = DOWN_arrow;
197+
} else {
198+
return; // Ignore diagonal movements
199+
}
200+
201+
updateDisplay(); // Update OLED only when movement occurs
202+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include <SPI.h>
2+
#include <Bitcraze_PMW3901.h>
3+
#include <WiFi.h>
4+
#include <ESPAsyncWebServer.h>
5+
6+
// WiFi credentials
7+
const char* ssid = "SSID";
8+
const char* password = "PASSWORD";
9+
10+
// PMW3901 (CS pin on GPIO 5)
11+
Bitcraze_PMW3901 flow(5);
12+
13+
// Web server on port 80
14+
AsyncWebServer server(80);
15+
16+
// Frame buffer (35x35 = 1225 bytes)
17+
char frame[35 * 35];
18+
19+
void setup() {
20+
Serial.begin(115200);
21+
22+
// Initialize PMW3901
23+
if (!flow.begin()) {
24+
Serial.println("PMW3901 init failed");
25+
while (1); // halt
26+
}
27+
28+
flow.enableFrameBuffer();
29+
Serial.println("PMW3901 frame buffer enabled");
30+
31+
// Connect to Wi-Fi
32+
WiFi.begin(ssid, password);
33+
WiFi.setSleep(false); // improves performance
34+
while (WiFi.status() != WL_CONNECTED) {
35+
delay(1000);
36+
Serial.println("Connecting to WiFi...");
37+
}
38+
39+
Serial.print("Connected. IP address: ");
40+
Serial.println(WiFi.localIP());
41+
42+
// Serve HTML UI
43+
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
44+
String html = R"rawliteral(
45+
<!DOCTYPE html>
46+
<html>
47+
<head>
48+
<title>PMW3901 Frame Buffer</title>
49+
<style>
50+
canvas {
51+
display: block;
52+
margin: auto;
53+
image-rendering: pixelated;
54+
width: 350px;
55+
height: 350px;
56+
border: 1px solid black;
57+
}
58+
body {
59+
font-family: sans-serif;
60+
background: #111;
61+
color: #fff;
62+
text-align: center;
63+
}
64+
#fps {
65+
margin: 10px;
66+
font-size: 1.2em;
67+
}
68+
</style>
69+
</head>
70+
<body>
71+
<h1>PMW3901 Frame Buffer</h1>
72+
<div id="fps">FPS: 0</div>
73+
<canvas id="frameBuffer" width="35" height="35"></canvas>
74+
75+
<script>
76+
const canvas = document.getElementById('frameBuffer');
77+
const ctx = canvas.getContext('2d');
78+
const imageData = ctx.createImageData(35, 35);
79+
80+
// Ironhot pseudo-color palette (33 entries)
81+
const ironhot = [
82+
[0, 0, 0], [35, 0, 0], [64, 0, 0], [96, 0, 0], [128, 0, 0], [160, 0, 0],
83+
[192, 0, 0], [224, 0, 0], [255, 0, 0], [255, 32, 0], [255, 64, 0],
84+
[255, 96, 0], [255, 128, 0], [255, 160, 0], [255, 192, 0], [255, 224, 0],
85+
[255, 255, 0], [224, 255, 32], [192, 255, 64], [160, 255, 96],
86+
[128, 255, 128], [96, 255, 160], [64, 255, 192], [32, 255, 224],
87+
[0, 255, 255], [0, 224, 255], [0, 192, 255], [0, 160, 255],
88+
[0, 128, 255], [0, 96, 255], [0, 64, 255], [0, 32, 255], [0, 0, 255]
89+
];
90+
91+
let lastTime = performance.now();
92+
93+
async function fetchFrameBuffer() {
94+
try {
95+
const response = await fetch('/data');
96+
const buffer = await response.arrayBuffer();
97+
const data = new Uint8Array(buffer);
98+
99+
for (let i = 0; i < data.length; i++) {
100+
const val = data[i];
101+
const colorIndex = Math.floor((val / 255) * (ironhot.length - 1));
102+
const [r, g, b] = ironhot[colorIndex];
103+
const index = i * 4;
104+
imageData.data[index] = r;
105+
imageData.data[index + 1] = g;
106+
imageData.data[index + 2] = b;
107+
imageData.data[index + 3] = 255;
108+
}
109+
110+
ctx.putImageData(imageData, 0, 0);
111+
112+
const now = performance.now();
113+
const fps = (1000 / (now - lastTime)).toFixed(1);
114+
lastTime = now;
115+
document.getElementById('fps').innerText = `FPS: ${fps}`;
116+
117+
requestAnimationFrame(fetchFrameBuffer);
118+
} catch (err) {
119+
console.error("Fetch error:", err);
120+
setTimeout(fetchFrameBuffer, 100);
121+
}
122+
}
123+
124+
fetchFrameBuffer();
125+
</script>
126+
</body>
127+
</html>
128+
)rawliteral";
129+
request->send(200, "text/html", html);
130+
});
131+
132+
// Binary data response
133+
server.on("/data", HTTP_GET, [](AsyncWebServerRequest* request) {
134+
flow.readFrameBuffer(frame);
135+
request->send_P(200, "application/octet-stream", (uint8_t*)frame, sizeof(frame));
136+
});
137+
138+
server.begin();
139+
}
140+
141+
void loop() {
142+
// Nothing here
143+
}

0 commit comments

Comments
 (0)