/*************************************************************************
 * Filename: rhGeiger.ino                                                *
 * Author:   Brian K. Gauger (based loosely on code by Alex Boguslavsky) *                                          *
 * Date:     11 Oct 2018                                                 *
 * Purpose:  Arduino code for http://rhelectronics.net v3.00 board,      *
 *           Serial Monitor version                                      *
 *                                                                       *
 * Arduino IDE version: 1.0.6                                            *
 * Executable Size: ~5.6 kbytes                                          *
 *                                                                       *
 * Copyright 2018 Brian K. Gauger                                        *
 *                                                                       *
 * Licensed under terms of Creative Commons Attribution-ShareAlike 4.0   *
 * International (CC BY-SA 4.0). You can do pretty much anything you     *
 * want with this code, provided you:                                    *
 *      a) Give me credit somewhere in the comments, and                 *
 *      b) Distribute your modified code under the same terms.           *
 *************************************************************************
 *                                                                       *
 * ===================================================================== *
 * Speaking of credit... MANY THANKS to Alex Boguslavsky for developing  *
 * the rhGeiger kit, and for the original code that inspired this!       *
 * ===================================================================== *

 *************************************************************************
 *
 * IMPORTANT NOTE:
 * ===============
 * The radiation levels reported by your Geiger Kit are APPROXIMATE only!
 * GM tubes vary greatly in terms of sensitivity to alpha, beta, and
 * gamma radiation. Some good info at:
 * https://sites.google.com/site/diygeigercounter/gm-tubes-supported
 *
 * If you need the CPM to microSievert conversion factor for GM tubes
 * OTHER than the SBM-20, this is a good place to begin looking.
 *
 * Remember, your unit is NOT calibrated to a standardized source.
 * So, take your readings with a large grain of salt substitute (a slightly
 * radioactive "check source"! A small plastic bag of KCl laid on top of my
 * SBM-20 yields about 6x background in my area. Your results will vary).
 */

 /////////////////////////////////////////////////////////
 // HARDWARE CONNECTIONS --                             //
 // A) Connect Geiger PCB INT output to Arduino pin 2.  //
 // B) Connect  Geiger PCB & Arduino grounds together.  //
 // C) Ensure C-INT (103, 0.01 uF) is soldered on the   //
 //    Geiger PCB.                                      //
 /////////////////////////////////////////////////////////

 // Averaging (logging) period in milliseconds, typically 15000-60000.   
#define AVG_PERIOD  15000
#define ONE_MINUTE  60000

// I'm using the SBM-20 Geiger-Muller (GM) tube with my kit. Conversion
// factors for other GM tubes may be found scattered throughout the Web.   

#define SBM_20

#ifdef SBM_20
#define CONV_FACTOR 0.0057   // SBM-20 counts to uSv/hr multiplier
#endif


#include 

//PubSubClient library for MQTT
#include 


//ethernet related includes
#include 
#include 							//ethernet2 for non-STM32

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
#if defined(WIZ550io_WITH_MACADDRESS) // Use assigned MAC address of WIZ550io
;
#else
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
#endif  



// Initialize the Ethernet client library

EthernetClient ethClient;

//MQTT

//MQTT sever address
#define MQTT_SERVER "192.168.107.11"  

void MQTTCallback(char* topic, byte* payload, unsigned int length);		//function prototype for MQTT callback

char const* MQTTClientName = "geiger";								//MQTT client name. Keep short, don't waste RAM
const char TelemetryTopic[] = "/geiger/tele/";					//Suffix added to board topic for telemetry heatbeat
const char CountTopic[] = "/geiger/cpm/";
const char DoseTopic[] = "/geiger/dose/";

PubSubClient MQTTClient(MQTT_SERVER, 1883, MQTTCallback, ethClient);	//pass Ethernet object to PubSubClient and create MQTT client



unsigned long counts; // # of raw GM Tube events
unsigned long cpm;				// Counts Per Minute (CPM)
unsigned int  mult;   // CPM = (counts in a given interval) * multiplier

char CountString[16];
char DoseString[16];


// Interrupt handler that counts raw events from Geiger Kit
void tube_impulse() {
	counts++;
}


void ConnectToMQTTBroker() {


	// Loop until connected to MQTT broker
	while (!MQTTClient.connected()) {
		Serial.println(F("MQTT: Attempting connection..."));

		//if connected, subscribe to the relay topics as BoardTopic/relay number
		if (MQTTClient.connect((char*)MQTTClientName)) {
			Serial.println(F("MQTT: Connected"));

		}
	}
}

void MQTTCallback(char* topic, byte* payload, unsigned int length) {
	//function called when MQTT message received

}


void setup()
{
	counts = 0;
	cpm = 0;

	// Initialize Serial communications
	Serial.begin(9600);

	Serial.println(F("Boot"));

	// start the Ethernet and obtain an address via DHCP
	Serial.println(F("Start: Ethernet..."));

	if (Ethernet.begin(mac) == 0) {
		Serial.println(F("FAIL: Ethernet: No DHCP."));

	}


	Serial.print(F("Success: Ethernet. DHCP IP: "));
	Serial.println(Ethernet.localIP());

	delay(3000);

	ConnectToMQTTBroker();							//connect to MQTT broker


	// Determine multiplier for your log period
	mult = ONE_MINUTE / AVG_PERIOD;

	pinMode(PA0, INPUT);                          // Set pin 2 up for GM tube event interrupts
	digitalWrite(PA0, HIGH);                      // Use internal pullup resistor
 


	//attachInterrupt(0, tube_impulse, FALLING);
	attachInterrupt(digitalPinToInterrupt(PA0), tube_impulse, FALLING);

	Serial.print(F("First reading in "));
	Serial.print(AVG_PERIOD / 1000);
	Serial.println(F(" sec..."));
	
}

void loop()
{

	//reconnect if connection is lost
	if (!MQTTClient.connected()) { ConnectToMQTTBroker(); }

	MQTTClient.loop();									//maintain the MQTT connection

	// Elapsed time stuff
	static unsigned long then;
	unsigned long now = millis();

	// Approx radiation level in microsieverts
	double uSv;

	switch (Ethernet.maintain()) {
	case 1:
		//renewed fail
		Serial.println(F("ERROR: DHCP Renewal Failure"));
		break;

	case 2:
		//renewed success
		Serial.println(F("SUCCESS: DHCP Renew"));
		//print your local IP address:
		Serial.print(F("IP Address: "));
		Serial.println(Ethernet.localIP());
		break;

	case 3:
		//rebind fail
		Serial.println(F("ERROR: Rebind failure"));
		break;

	case 4:
		//rebind success
		Serial.println(F("SUCCESS: Rebind"));
		//print your local IP address:
		Serial.print(F("IP Address: "));
		Serial.println(Ethernet.localIP());
		break;

	default:
		//nothing happened
		break;
	}



	if (now - then > AVG_PERIOD) {
		then = now;
		if (counts) {                     // i.e., if (counts != 0)
			cpm = counts * mult;
			uSv = cpm * CONV_FACTOR;
		}
		else {
			uSv = 0;
		}
		Serial.print(F("Counts: "));
		Serial.println(counts);
		Serial.print(F("CPM: "));
		Serial.println(cpm);
		Serial.print(F("uSv/hr: "));
		Serial.println(uSv, 4);          // Display 4 decimal places
		
		//convert both numbers to cstrings for MQTT publish
		itoa(cpm, CountString, 10);
		dtostrf(uSv, 5, 5, DoseString);


		counts = 0, cpm = 0;							//reset the counts fo rnext loop
	
		Serial.print(F("MQTT Publish:"));
		Serial.print(CountTopic);
		Serial.println(CountString);
		
		Serial.print(F("MQTT Publish:"));
		Serial.print(DoseTopic);
		Serial.println(DoseString);


		MQTTClient.publish(CountTopic, CountString);					
		MQTTClient.publish(DoseTopic, DoseString);
	}
	
}