Skip to content

Commit 872402c

Browse files
authored
Add files via upload
1 parent 96e8a20 commit 872402c

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries
2+
//
3+
// SPDX-License-Identifier: MIT
4+
//
5+
// Based on Adafruit-DVI-HSTX library code written by Jeff Epler
6+
// Version for the Adafruit Fruit Jam
7+
8+
#include <Adafruit_dvhstx.h>
9+
10+
// Display configuration for text mode in Adafruit-DVI-HSTX
11+
const int SCREEN_WIDTH = 91;
12+
const int SCREEN_HEIGHT = 30;
13+
14+
// Animation speed (lower = faster)
15+
// Adjust this value to change the speed of the animation
16+
const int ANIMATION_SPEED = 120; // milliseconds between updates
17+
18+
#if defined(ADAFRUIT_FEATHER_RP2350_HSTX)
19+
DVHSTXPinout pinConfig = ADAFRUIT_FEATHER_RP2350_CFG;
20+
#elif defined(ADAFRUIT_METRO_RP2350)
21+
DVHSTXPinout pinConfig = ADAFRUIT_METRO_RP2350_CFG;
22+
#elif defined(ARDUINO_ADAFRUIT_FRUITJAM_RP2350)
23+
DVHSTXPinout pinConfig = ADAFRUIT_FRUIT_JAM_CFG;
24+
#elif (defined(ARDUINO_RASPBERRY_PI_PICO_2) || defined(ARDUINO_RASPBERRY_PI_PICO_2W))
25+
DVHSTXPinout pinConfig = ADAFRUIT_HSTXDVIBELL_CFG;
26+
#else
27+
// If your board definition has PIN_CKP and related defines,
28+
// DVHSTX_PINOUT_DEFAULT is available
29+
DVHSTXPinout pinConfig = DVHSTX_PINOUT_DEFAULT;
30+
#endif
31+
32+
DVHSTXText display(pinConfig);
33+
// If you get the message "error: 'DVHSTX_PINOUT_DEFAULTx' was not declared"
34+
// then you need to give the pins numbers explicitly, like the example below.
35+
// The order is: {CKP, D0P, D1P, D2P}.
36+
//
37+
// DVHSTXText display({12, 14, 16, 18});
38+
39+
// Define structures for character streams
40+
struct CharStream {
41+
int x; // X position
42+
int y; // Y position (head of the stream)
43+
int length; // Length of the stream
44+
int speed; // How many frames to wait before moving
45+
int countdown; // Counter for movement
46+
bool active; // Whether this stream is currently active
47+
char chars[30]; // Characters in the stream
48+
};
49+
50+
const static TextColor colors[] = {
51+
TextColor::TEXT_BLACK, TextColor::TEXT_RED, TextColor::TEXT_GREEN,
52+
TextColor::TEXT_BLUE, TextColor::TEXT_YELLOW, TextColor::TEXT_MAGENTA,
53+
TextColor::TEXT_CYAN, TextColor::TEXT_WHITE,
54+
};
55+
56+
const static TextColor background_colors[] = {
57+
TextColor::BG_BLACK, TextColor::BG_RED, TextColor::BG_GREEN,
58+
TextColor::BG_BLUE, TextColor::BG_YELLOW, TextColor::BG_MAGENTA,
59+
TextColor::BG_CYAN, TextColor::BG_WHITE,
60+
};
61+
62+
// Array of character streams - increased for higher density
63+
// To fill 60-75% of the screen width (91 chars), we need around 55-68 active streams
64+
CharStream streams[250]; // Allow for decent density
65+
66+
// Stream creation rate (higher = more frequent new streams)
67+
const int STREAM_CREATION_CHANCE = 80; // % chance per frame to create new stream
68+
69+
// Initial streams to create at startup
70+
const int INITIAL_STREAMS = 30;
71+
72+
// Random characters that appear in the streams
73+
const char matrixChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?/\\";
74+
const int numMatrixChars = sizeof(matrixChars) - 1;
75+
76+
// Function declarations
77+
void initStreams();
78+
void updateStreams();
79+
void drawStream(CharStream &stream);
80+
void createNewStream();
81+
char getRandomChar();
82+
83+
void setup() {
84+
// Initialize the display
85+
display.begin();
86+
display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK);
87+
display.clear();
88+
89+
// Seed the random number generator
90+
randomSeed(analogRead(A0));
91+
92+
// Initialize all streams
93+
initStreams();
94+
}
95+
96+
void loop() {
97+
// Update and draw all streams
98+
updateStreams();
99+
100+
// Randomly create new streams at a higher rate
101+
if (random(100) < STREAM_CREATION_CHANCE) {
102+
createNewStream();
103+
}
104+
105+
// Control animation speed
106+
delay(ANIMATION_SPEED);
107+
}
108+
109+
void initStreams() {
110+
// Initialize all streams as inactive
111+
for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) {
112+
streams[i].active = false;
113+
}
114+
115+
// Create more initial streams for immediate visual impact
116+
for (int i = 0; i < INITIAL_STREAMS; i++) {
117+
createNewStream();
118+
}
119+
}
120+
121+
void createNewStream() {
122+
// Find an inactive stream
123+
for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) {
124+
if (!streams[i].active) {
125+
// Initialize the stream
126+
streams[i].x = random(SCREEN_WIDTH);
127+
streams[i].y = random(5) - 5; // Start above the screen
128+
streams[i].length = random(5, 20);
129+
streams[i].speed = random(1, 4);
130+
streams[i].countdown = streams[i].speed;
131+
streams[i].active = true;
132+
133+
// Fill with random characters
134+
for (int j = 0; j < streams[i].length; j++) {
135+
streams[i].chars[j] = getRandomChar();
136+
}
137+
138+
return;
139+
}
140+
}
141+
}
142+
143+
void updateStreams() {
144+
display.clear();
145+
146+
// Count active streams (for debugging if needed)
147+
int activeCount = 0;
148+
149+
for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) {
150+
if (streams[i].active) {
151+
activeCount++;
152+
streams[i].countdown--;
153+
154+
// Time to move the stream down
155+
if (streams[i].countdown <= 0) {
156+
streams[i].y++;
157+
streams[i].countdown = streams[i].speed;
158+
159+
// Change a random character in the stream
160+
int randomIndex = random(streams[i].length);
161+
streams[i].chars[randomIndex] = getRandomChar();
162+
}
163+
164+
// Draw the stream
165+
drawStream(streams[i]);
166+
167+
// Check if the stream has moved completely off the screen
168+
if (streams[i].y - streams[i].length > SCREEN_HEIGHT) {
169+
streams[i].active = false;
170+
}
171+
}
172+
}
173+
}
174+
175+
void drawStream(CharStream &stream) {
176+
for (int i = 0; i < stream.length; i++) {
177+
int y = stream.y - i;
178+
179+
// Only draw if the character is on screen
180+
if (y >= 0 && y < SCREEN_HEIGHT) {
181+
display.setCursor(stream.x, y);
182+
183+
// Set different colors/intensities based on position in the stream
184+
if (i == 0) {
185+
// Head of the stream is white (brightest)
186+
display.setColor(TextColor::TEXT_WHITE, TextColor::BG_BLACK, TextColor::ATTR_NORMAL_INTEN);
187+
} else if (i < 3) {
188+
// First few characters are bright green
189+
display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_NORMAL_INTEN);
190+
} else if (i < 6) {
191+
// Next few are medium green
192+
display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_LOW_INTEN);
193+
} else {
194+
// The rest are dim green
195+
display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_V_LOW_INTEN);
196+
}
197+
198+
// Draw the character
199+
display.write(stream.chars[i]);
200+
}
201+
}
202+
203+
// Occasionally change a character in the stream
204+
if (random(100) < 25) { // 25% chance
205+
int idx = random(stream.length);
206+
stream.chars[idx] = getRandomChar();
207+
}
208+
}
209+
210+
char getRandomChar() {
211+
return matrixChars[random(numMatrixChars)];
212+
}

0 commit comments

Comments
 (0)