// Listing 10.4. Standard SABB
const byte myAddress = '2'; // zakres adresów 0 – 255
const int bufferSize = 64;  // 64 odpowiada długości bufora portu szeregowego
byte txBuffer[bufferSize];  // bufor na dane do wysłania do urządzenia slave
byte rxBuffer[bufferSize];  // bufor na dane odebrane z urządzenia slave
volatile byte rxBufferSlave[bufferSize]; // przechowywanie danych, jeżeli urządzenie jest slave
volatile boolean flag = true; // zmiana flagi stanu diody LED

void setup() {
  Serial.begin(115200); // otwarcie połączenia szeregowego
  PORTB |= 0b00000100; // ustawienie stanu wysokiego na linii SS
  while (!(PINB & 0b00000100)); // oczekiwanie na inicjalizację, jeżeli stan na linii SS jest zewnętrznie ustawiony na niski 
  initSPI(); // przygotowanie do połączenia z siecią
  txBuffer[0] = 0b00000000; // wpisanie bajtu zerowego do bufora wysyłającego
  transferSPI(1); // wysłanie bajtu zerowego, aby zwolnić oczekujące urządzenia
  initSPI(); // ustaw stan jałowy na komunikacji płyta-płyta
  Serial.println("Gotowy"); // informacja o pełnej inicjalizacji płyty
}
void loop() {
  if (Serial.available()) {
    delay(1000); // oczekiwanie 1 s na odebranie danych szeregowych
    int count = 1; // zapisanie danych w tabeli, począwszy od 2. pozycji
    txBuffer[0] = 0b00000000; // wysłanie najpierw bajtu zerowego 
    while (Serial.available()) {
      txBuffer[count] = Serial.read(); // zapisanie bufora szeregowego do txBuffer
      count++; 
    }
    Serial.flush(); // wyczyszczenie bufora szeregowego
    transferSPI(count); // wysłanie i odebranie danych jako master
    printBuffer(count); // wyświetlenie danych wysłanych i odebranych
    initSPI(); // powrót do stanu jałowego
  }
  if (flag == true ) { // flaga ustawiona na true, jeżeli urządzenie zaadresowane przez mastera
    PORTB = (~(PINB << 7) >> PINB7); // zmiana stanu diody LED
    flag = false; // skasowanie flagi
  }
}
void initSPI() { // ustawienie stanu jałowego połączenia
  DDRB |= 0b00000001;  // wyjście LED
  DDRB &= 0b11000011;  // wejście MOSI MISO SCK SS
  PORTB |= 0b00000100; // ustawienie stanu wysokiego na linii slave select
  PORTB &= 0b11000111; // ustawienie stanu niskiego na linii MISO MOSI SCK
  SPCR = 0b11000000;   // SPIE, SPE, SLAVE, MODE0, CLOCK DIV_4
  sei(); // globalne włączenie przerwań
}

int printBuffer(int nBytes) { // wyświetlenie danych wysyłanych i odbieranych, jeżeli urządzenie jest typu master
  Serial.println();
  Serial.write (txBuffer, nBytes);
  Serial.println();
  Serial.write (rxBuffer, nBytes);
  Serial.println();
}
int transferSPI(int txBytes) {
  cli(); // globalne wyłączenie przerwań
  SPCR |= 0b00010000;  // ustawienie trybu SPI master
  DDRB |= 0b00101100;  // wyjście MOSI SCK SS
  DDRB &= 0b11101111;  // wejście MISO
  PORTB &= 0b11111011; // stan wysoki na linii slave select
  int count = 0;
  delay(50); // czekanie, aż dołączone urządzenia obsłużą przerwanie; 50 jest bardzo bezpieczną wartością
  while (count < txBytes) { // wykonywanie pętli, aż wszystkie dane zostaną wysłane
    SPDR = txBuffer[count]; // rozpoczęcie wysyłania bajtu przez wpisanie go do rejestru SPDR
    while (!(SPSR & (1 << SPIF))); // oczekiwanie na zakończenie transmisji
    rxBuffer[count] = SPDR; // odczyt odebranego bajtu
    count++;
  }
  PORTB |= 0b00000100; // ustawienia stanu wysokiego na linii SS
}
ISR(SPI_STC_vect) { // wektor przerwania SPI
  int count = 0;
  if (!(PINB & 0b00000100)) { // wejście, jeżeli stan SS jest niski
    while (!(PINB & 0b00000100)) { // pętla, dopóki stan SS jest niski
      while (!(SPSR & (1 << SPIF))); // oczekiwanie na zakończenie transmisji danych
      rxBufferSlave[count] = SPDR; // odczyt rejestru  SPDR
      if (rxBufferSlave[0] == myAddress) {DDRB |= 0b00010000;} // ustawienie linii MISO jako wyjścia, jeżeli adres się zgadza
      SPDR = rxBufferSlave[count]; // wpisanie danych do wysłania do rejestru SPDR
      count++;
    }
    if (rxBufferSlave[0] == myAddress) {flag = true;} // ustawienie flagi zmiany diody LED, jeżeli adres się zgadza
    initSPI(); // powrót do stanu jałowego połączenia
  }
}

