#include <Arduino.h>
#define CLK 13
#define DIN 11
#define CS 10
#define X_SEGMENTS 8
#define Y_SEGMENTS 4
#define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS)
byte fb[8 * NUM_SEGMENTS];
byte nextFb[8 * NUM_SEGMENTS];
void shiftOutAll(byte send_to_address, byte *send_this_data, int len) {
digitalWrite(CS, LOW);
shiftOut(DIN, CLK, MSBFIRST, send_to_address);
for (int i = 0; i < len; i++) {
shiftOut(DIN, CLK, MSBFIRST, send_this_data[i]);
}
digitalWrite(CS, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(CLK, OUTPUT);
pinMode(DIN, OUTPUT);
pinMode(CS, OUTPUT);
byte initData[1] = {0x00};
shiftOutAll(0x0f, initData, 1);
byte intensityData[1] = {0x07};
shiftOutAll(0x0b, intensityData, 1);
byte scanLimitData[1] = {0x01};
shiftOutAll(0x0c, scanLimitData, 1);
byte powerDownData[1] = {0x0f};
shiftOutAll(0x0a, powerDownData, 1);
byte testModeData[1] = {0x00};
shiftOutAll(0x09, testModeData, 1);
randomSeed(analogRead(0));
for (int i = 0; i < 1400; i++) {
int x = random(0, X_SEGMENTS * 8);
int y = random(0, Y_SEGMENTS * 8);
set_pixel(x, y, true);
}
}
void loop() {
updateGameOfLife();
show();
delay(0);
}
void updateGameOfLife() {
for (int i = 0; i < 8 * NUM_SEGMENTS; i++) {
nextFb[i] = fb[i];
}
for (int y = 0; y < Y_SEGMENTS * 8; y++) {
for (int x = 0; x < X_SEGMENTS * 8; x++) {
int neighbors = countNeighbors(x, y);
if (fb[y * X_SEGMENTS + x / 8] & (1 << (7 - (x % 8)))) {
if (neighbors < 2 || neighbors > 3) {
set_next_pixel(x, y, false);
}
} else {
if (neighbors == 3) {
set_next_pixel(x, y, true);
}
}
}
}
for (int i = 0; i < 8 * NUM_SEGMENTS; i++) {
fb[i] = nextFb[i];
}
}
int countNeighbors(int x, int y) {
int count = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
int nx = (x + dx + X_SEGMENTS * 8) % (X_SEGMENTS * 8);
int ny = (y + dy + Y_SEGMENTS * 8) % (Y_SEGMENTS * 8);
if (fb[ny * X_SEGMENTS + nx / 8] & (1 << (7 - (nx % 8)))) count++;
}
}
return count;
}
void set_next_pixel(uint8_t x, uint8_t y, bool state) {
byte *addr = &nextFb[x / 8 + y * X_SEGMENTS];
byte mask = 128 >> (x % 8);
if (state) {
*addr |= mask;
} else {
*addr &= ~mask;
}
}
void set_pixel(uint8_t x, uint8_t y, bool state) {
byte *addr = &fb[x / 8 + y * X_SEGMENTS];
byte mask = 128 >> (x % 8);
if (state) {
*addr |= mask;
} else {
*addr &= ~mask;
}
}
void show() {
for (byte row = 0; row < 8; row++) {
digitalWrite(CS, LOW);
byte segment = NUM_SEGMENTS;
while (segment--) {
byte x = segment % X_SEGMENTS;
byte y = segment / X_SEGMENTS * 8;
byte addr = (row + y) * X_SEGMENTS;
if (segment & X_SEGMENTS) {
shiftOut(DIN, CLK, MSBFIRST, 8 - row);
shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]);
} else {
shiftOut(DIN, CLK, MSBFIRST, 1 + row);
shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]);
}
}
digitalWrite(CS, HIGH);
}
}