/* ==============================
 * Ten kod (przy założeniu, że jest stosowany oficjalny moduł sieciowy Arduino Ethernet)
 * aktualizuje kanał Pachube, wysyłając wartości z czujnika analogowego, i pobiera wartości z serwisu Pachube;
 * dzięki temu system może stosować zarówno czujniki lokalne, jak i czujniki zdalne.
 *
 * Szkic został przetestowany z wersją Arduino 1.0.
 *
 * Serwis Pachube znajduje się pod adresem www.pachube.com - kod nawiązujący połączenie, tagujący dane i operujący na danych w czasie rzeczywistym
 * został opracowany przez użytkownika usman (www.haque.co.uk) w maju 2009 roku.
 * Kod można swobodnie kopiować, rozpowszechniać i wykorzystywać w dowolny inny sposób.
 *
 * W wersji 1.1 dodano nagłówek User-Agent i poprawiono parser HTTP z myślą o nowych nagłówkach serwisu Pachube.
 * W tej wersji szkic sprawdza też wartość funkcji millis().
 *
 * 
 * Moduł sieciowy jest podłączony do pinów nr 10, 11, 12 i 13.
 *
 * data utworzenia: 15 marca 2010
 * data modyfikacji: 4 września 2010
 * autor: Tom Igoe
 *
 * http://www.tigoe.net/pcomp/code/category/arduinowiring/873
 * Ten kod jest dostępny publicznie.
 *
 * Kod został zmodyfikowany przez Patricka Di Justo (jesienią 2011).
 */

#include <SPI.h>
#include <Ethernet.h>

// Tutaj należy przypisać adres MAC modułu sieciowego.
// Nowsze wersje modułów sieciowych mają naklejki z nadrukowanymi adresami MAC.
// Wpisz adres swojego modułu:

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};


// Inicjalizuje obiekt biblioteki:
EthernetClient client;

long lastConnectionTime = 0; // reprezentuje czas nawiązania ostatniego połączenia z serwerem (w milisekundach)
boolean lastConnected = false; // stan połączenia podczas ostatniego wykonywania głównej pętli
const int postingInterval = 15000; // opóźnienie pomiędzy kolejnymi aktualizacjami w serwisie Pachube.com

int minuteFactor = 60000 / postingInterval;

int geiger_input = 2;
long timePreviousMeassure = 0;
long countPerMinute = 0;
long count = 0;
float radiationValue = 0.0;

// Definiuje pin SPI dla karty SD:
#define SD_CARD 4


// Współczynnik konwersji dla wykrywacza promieniowania SBM-20:
#define CONV_FACTOR 0.0057

// Znaki X należy zastąpić własnym identyfikatorem kanału w serwisie Pachube:
#define SHARE_FEED_ID XXXXX

// Znaki X należy zastąpić kluczem API w serwisie Pachube:
#define PACHUBE_API_KEY "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // wpisz swój klucz API 

void setup() 
{

  // W razie stosowania modułu sieciowego z czytnikiem kart SD firmy Wiznet poniższe dwa wiersze
  // są konieczne, aby tymczasowo wyłączyć czytnik kart SD. Dzięki temu
  // port sieciowy tego modułu będzie działał prawidłowo.

  pinMode(SD_CARD, OUTPUT);
  digitalWrite(SD_CARD, HIGH);


  // Uruchamia port szeregowy:
  Serial.begin(9600);
  // Uruchamia połączenie sieciowe:
  delay(1000);


  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Nie udało się skonfigurować sieci za pomocą DHCP");
    // W takim przypadku dalsze działanie nie ma sensu:
    for(;;)
      ;
  }

  // daje modułowi sieciowemu czas na uruchomienie:
  delay(1000);

  // Ustawia stan wejścia licznika Geigera równy HIGH, aby można było określić 
  // zmianę tego stanu. Zostanie użyte przerwanie nr 0 platformy Arduino połączone
  // z pinem cyfrowym nr 2 reprezentowanym przez zmienną geiger_input.

  pinMode(geiger_input, INPUT);
  digitalWrite(geiger_input,HIGH);

  attachInterrupt(0,countPulse,CHANGE);

}

void loop() 

{

  if (millis()-timePreviousMeassure > postingInterval)

  {

    countPerMinute = count*minuteFactor;
    radiationValue = countPerMinute * CONV_FACTOR;
    timePreviousMeassure = millis();
    Serial.println(count);
    Serial.print("cpm = ");
    Serial.print(countPerMinute,DEC);
    Serial.print(" - ");
    Serial.print("uSv/h = ");
    Serial.println(radiationValue,4);
    count = 0;

  }

  // Jeśli otrzymano dane przychodzące za pośrednictwem połączenia sieciowego,
  // program przekazuje je do portu szeregowego. Wyświetlanie tych danych ma na celu wyłącznie
  // ułatwienie diagnozowania szkicu:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // Jeśli połączenie sieciowe nie jest dostępne, ale pętla została wykonana
  // przynajmniej raz, działanie klienta zostaje zatrzymane:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // Jeśli połączenie sieciowe nie jest dostępne i jeśli minęło dziesięć sekund
  // od ostatniego połączenia, program ponownie nawiązuje połączenie i wysyła dane:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    sendData(radiationValue);
  }

  // zapisuje stan połączenia dla następnej iteracji
  // pętli:
  lastConnected = client.connected();
}

void countPulse()

{
  detachInterrupt(0);
  count++;
  digitalWrite(13,HIGH);
  while(digitalRead(2)==0){
  }
  digitalWrite(13,LOW);

  attachInterrupt(0,countPulse,CHANGE);
}

// Ta metoda nawiązuje połączenie HTTP z serwerem:
void sendData(int thisData) {
  // Jeśli udało się nawiązać połączenie:
  if (client.connect("www.pachube.com", 80)) {
    Serial.println("connecting...");
    // wysyła żądanie PUT protokołu HTTP. 
    // Tutaj należy wpisać adres używanego kanału:
    client.print("PUT /api/");
    client.print(SHARE_FEED_ID);
    client.print(".csv HTTP/1.1\nHost: pachube.com\nX-PachubeApiKey: ");
    client.print(PACHUBE_API_KEY);
    client.print("\nContent-Length: ");

    // Oblicza długość danych przekazanych przez czujnik (w bajtach):
    int thisLength = getLength(thisData);
    client.println(thisLength, DEC);

    // ostatnie elementy żądania HTTP PUT:
    client.print("Content-Type: text/csv\n");
    client.println("Connection: close\n");

    // To jest właściwa treść żądania PUT:
    client.println(thisData, DEC);

    // Zapisuje czas nawiązania połączenia:
    lastConnectionTime = millis();
  } 

  else 

  {
    // jeśli nie można nawiązać połączenia:
    Serial.println("Nie można nawiązać połączenia.");
  }

}

// Ta metoda oblicza liczbę cyfr składających się na
// odczyt przekazany przez czujnik. Ponieważ każda cyfra jest znakiem ASCII
// reprezentowanym przez jeden bajt, liczba cyfr jest równa
// liczbie bajtów:

int getLength(int someValue) 

{

  // istnieje co najmniej jeden bajt:
  int digits = 1;
  // wielokrotnie dzieli tę wartość przez 10, 
  // dodając za każdym razem jedną cyfrę do licznika
  // aż do osiągnięcia wartości 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }

  // Zwraca liczbę cyfr:
  return digits;
}

