/*
   Arduino code for Individual control over each pin
   Support for 40+ 74HC595 8 bit shift registers
   http://bildr.org/2011/02/74hc595/
*/
// chatGPT character set for animation
const byte charSet[] = {
  // Alternating / Blinking Patterns
  0b01010101, // 55 - Alternating bits
  0b10101010, // AA - Inverted alternating
  0b11001100, // Double pairs
  0b00110011, // Double pairs inverted
  0b10011001, // Symmetric mirror
  0b01100110, // Symmetric mirror inverted
  // Sweeps / Crawlers (Left → Right)
  0b00000001,
  0b00000010,
  0b00000100,
  0b00001000,
  0b00010000,
  0b00100000,
  0b01000000,
  0b10000000,
  // Sweeps / Crawlers (Edges & pairs)
  0b10000001,
  0b11000011,
  0b11100111,
  0b11111111, // All on
  // 💡 Flash / Pulse / Fade
  0b00011000, // Center pulse
  0b00111100, // Medium pulse
  0b01111110, // Wide pulse
  0b00000000, // All off
  // Borders & Centered Shapes
  0b10000001,
  0b11000011,
  0b11100111,
  0b01111110,
  0b00111100,
  0b00011000,
  // Symmetric / Shape Patterns
  0b10011001,
  0b01100110,
  0b11100000,
  0b00000111,
  0b00111111,
  0b11111100,
  0b00110011,
  0b11001100,
  0b10100101,
  0b01011010,
  0b11110000,
  0b00001111,
  // Random / Chaotic-Looking Patterns
  0b10101001,
  0b10010110,
  0b01101010,
  0b11010101,
  0b00101001,
  0b10001110,
  0b11101000,
  0b00010111,
  // Duplicates for animation rhythm (optional reuse)
  0b11111111, // Flash all on
  0b00000000, // Flash all off
  0b10000001, // Outer borders
  0b11100000, // Edge-heavy left
  0b00000111, // Edge-heavy right
  0b11000011  // Edge blocks
};
const byte nChars = sizeof charSet / sizeof *charSet;
// Define ranges for each section of animation (start, length)
const byte animSections[][2] = {
  { 0, 6 },   // Alternating
  { 6, 8 },   // Left-to-Right Sweep
  {14, 4 },   // Edges & pairs
  {18, 4 },   // Flash / Pulse
  {22, 6 },   // Borders & Shapes
  {28,12 },   // Symmetric Patterns
  {40, 8 },   // Chaotic
  {48, 6 }    // Rhythmic repeats
};
const byte numSections = sizeof(animSections) / sizeof(animSections[0]);
// Timing
unsigned long lastUpdate = 0;
const unsigned int frameInterval = 777;      // Time between frames (ms)
const unsigned long sectionDuration = 9000;  // Time per section (ms)
unsigned long sectionStartTime = 0;
// Animation state
byte currentChar = 0;
byte currentSection = 0;
#define DATA_PIN  8  // Pin connected to DS of 74HC595
#define LATCH_PIN 9  // Pin connected to STCP of 74HC595
#define CLOCK_PIN 10 // Pin connected to SHCP of 74HC595
// How many of the shift registers
#define NUM_SHIFT_REGS 1
const uint8_t numOfRegisterPins = NUM_SHIFT_REGS * 8;
bool registers[numOfRegisterPins];
unsigned char countBits(int n)
{
    unsigned char count = 0;
    while (n) {
// printf(" %d\n", n);
        n &= (n - 1);
        count++;
    }
    return count;
}
unsigned char lsfr8X(unsigned char xx) {
// tune for polynomial: this is 0xa6
  if (xx == 1) return 0;
  if (xx == 0) return 2;
  char parity = countBits(xx & 0xa6) & 0x1;
  xx <<= 1;
  xx |= parity;
  return xx;
}
unsigned char seq = 0x5a;  // zero for zero zero, or retune
void setup() {
  Serial.begin(115200);
  Serial.println("\nchatGPT ANimation!\n");
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);
  clearRegisters();
  writeRegisters();
  sectionStartTime = millis();
}
void loop() {
  unsigned long now = millis();
  // Check if it's time to move to the next frame
  if (now - lastUpdate >= frameInterval) {
    lastUpdate = now;
    // Display current character
    byte start = animSections[currentSection][0];
    byte len = animSections[currentSection][1];
    byte pattern = charSet[start + (currentChar % len)];
    displayPattern(pattern);
    currentChar++;
  }
  // Move to next section if section duration elapsed
  if (now - sectionStartTime >= sectionDuration) {
    currentSection = (currentSection + 1) % numSections;
    currentChar = 0;
    sectionStartTime = now;
    Serial.print("Switching to section: ");
    Serial.println(currentSection);
  }
}
void displayPattern(byte pattern) {
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pattern);
  digitalWrite(LATCH_PIN, HIGH);
}
bool toggle = false;
void loop0() {
  for (unsigned char ii = 0; ii < nChars; ii++) {
    for (unsigned char jj = 0; jj < 8; jj++) {
      setRegisterPin(7 - jj, charSet[ii] & (1 << jj));
    }
    writeRegisters();
    delay(777);
  }
return;
  for (unsigned char ii = 0; ii < 8; ii++) {
    setRegisterPin(7 - ii, seq & (1 << ii));
    writeRegisters();
  }
  seq = lsfr8X(seq);
  delay(477);
} 
void clearRegisters() {
  // Reset all register pins
  for (int i = numOfRegisterPins - 1; i >= 0; i--) {
    registers[i] = LOW;
  }
}
void setRegisterPin(int index, int value) {
  // Set an individual pin HIGH or LOW
  registers[index] = value;
}
void writeRegisters() {
  // Set and display registers
  digitalWrite(LATCH_PIN, LOW);
  for (int i = numOfRegisterPins - 1; i >= 0; i--) {
    digitalWrite(CLOCK_PIN, LOW);
    digitalWrite(DATA_PIN, registers[i]);
    digitalWrite(CLOCK_PIN, HIGH);
  }
  digitalWrite(LATCH_PIN, HIGH);
}