/* Arduino#3 (2009) + Wiznet Ethernet-shield, location: 1. floor by the heat pump
Functions:
1) send commands to Toshiba heat pump using the IR-led in pin 3
2) read two OneWire buses with DS18B20, 12 bit resolution. Up to 8 temp sensors per bus, sensors supplied from +5V (not parasitic)
3) detect kWh meter pulses (S0) in pin 2
4) count pulses in pin 5 from the heat pump fan
5) switch on/off two resistors in parallel with the hp's ambient temp resistor (in pins 6 and 7)
6) communicate with RPi using UDP
7) drive room leds in pin 4 when commanded
18.3.2015 PROBLEMS: Has only 472 bytes of free RAM
CHANGED: Possible int / unsigned in problem
NOT DL To do: Could backup HP commands
*/
#include <OneWire.h>
#include <IRremote.h>
#include <SPI.h>  		    			   	// needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>      			  	// UDP library from: bjoern@cs.stanford.edu 12/30/2008
#include <MemoryFree.h>
#define maxbus 2
OneWire dss[] = { OneWire(8), OneWire(9) };
IRsend irsend;
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x55 };
IPAddress myip(192, 168, 100, 123);
IPAddress remote (192, 168, 100, 120);		// necessary or in some situations can send 0.0.0.0
char packetBuffer[64];
EthernetUDP Udp;
byte temp[9];
volatile unsigned long tint = 0;			// interrupt time [ms], Wiznet module does not use pin 2
byte intpin = 2;							// INT0, kWh meter gives 1 pulse/Wh, this program can detect power up to > 2000 W
byte b[9] = { 0xf2, 0x0d, 0x03, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00 }; // Toshiba remote control bytes

void setup() {
	TCCR1A = 0x00;							// counter 1 in normal mode, OC1 disconnected
	TCCR1B = 0x07;							// external clock, rising edge
	pinMode (4, OUTPUT); 					// room leds
	pinMode (5, INPUT);						// CNT1 input pin
	digitalWrite(5, HIGH);					// pull-up
	pinMode (intpin, INPUT);
	pinMode (6, OUTPUT); 					// parallel resistor 0
	pinMode (7, OUTPUT); 					// parallel resistor 1
	digitalWrite(6, LOW);					//
	digitalWrite(7, LOW);					//
	pinMode (14, OUTPUT); 					// internal (normal) NTC resistor when pin 14 held low and high pulse in pin 15
	pinMode (15, OUTPUT); 					// external NTC resistor when high pulse in pin 14 and pin 15 held low
	digitalWrite(14, LOW);					// leave previous resistor selection in boot (bistable relay)
	digitalWrite(15, LOW);					//
	attachInterrupt (0, wh, FALLING);		// kWh meter pulse is 0-active
	Ethernet.begin(mymac, myip);
	Udp.begin(51432);
}
void sendString(char *strs) {
	Udp.beginPacket(Udp.remoteIP(), 51432);
	Udp.write(strs);
	Udp.endPacket();
}
float hextodec() {						// convert temp hex to decimal
	byte temb0, temb1, temb2;
	float temf;
	temb1 = 0x70 & (temp[1] << 4);				// no negative here, skip it
	temb0 = 0x0f & (temp[0] >> 4);
	temb2 = 0x0f & temp[0];
	temf = (temb1 | temb0) + (float)temb2 * 0.0625;
	return temf;
}
char *ftos3(float ave, int prec) {	
	char as[] = "1111111";
	char *a = as;	
	char *ret = a;
	long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
	int wpart = (int)ave;
	sprintf (a, "%d", wpart);	
	while (*a != '\0') a++;
	*a++ = '.';
	int decimal = abs((int)((ave - wpart) * p[prec]));
	if (prec == 1)
	    sprintf (a, "%01d", decimal);	
	else if (prec == 2)
	    sprintf (a, "%02d", decimal);	
	else if (prec == 3)
	    sprintf (a, "%03d", decimal);	
	else if (prec == 4)
	    sprintf (a, "%04d", decimal);	
	return ret;
}
void convert() {									// B0...4 and 7 are fixed
	byte vf[6] = { 0x00, 0x40, 0x60, 0x80, 0xa0, 0xc0 };	// fan codes: auto, 1, 2, 3, 4, 5
	byte ve[5] = { 0x00, 0x01, 0x02, 0x03, 0x07 };		// mode codes: auto, cool, dry, heat, off
	byte stiudp[4];
	byte s, tu = 0;
	b[8] = 0;
	for (s = 0; s < 4; ++s)
		stiudp[s] = packetBuffer[ s + 3 ] - '0';
	tu = stiudp[0] * 10 + stiudp[1] - 17;			// Temp code: 17 C = 0b0000, 18 C = 0b0001, 19 C = 0b0010 etc.
	b[5] = (tu << 4) & 0xf0;						// b7...b4 = T, b3...b0 fixed 0b0000
	b[6] = ((vf[stiudp[2]]) | (ve[stiudp[3]]));		// fan and mode byte from table
	for (s = 0; s < 8; s++)
		b[8] = (b[8]^b[s]);							// parity byte
}	
void sendToshiba() {
	byte a, r, s;
	irsend.sendTOSSUHeader();						// call the function to send the header
	for (s = 0; s < 9; ++s) {						// leading zeros dropped by SW, must invert bytes which start with '0'
		r = b[s] & 0x80;
		if (r == 0) {
			a = ~(b[s]);
			irsend.sendinvTOSSU(a, 8);}				// call the routine to send inverted byte
		else
			irsend.sendTOSSU(b[s], 8);} 			// send normal byte
	irsend.sendTOSSU(0x80, 1);						// "stop" bit
	irsend.space(8000);
}
byte StartConversion (byte bus, byte pow, OneWire dss) {
	if (dss.reset()) {								// '1' if a sensor pulled line down, otherwise '0'
		dss.skip();									// 'skip'-command = address all sensors on the bus
		dss.write(0x44, pow);					 	// all sensors convert temp (in parasite mode pow = 1, in +5V mode pow = 0)
		return 1;
	}
	else
		return 0;
}
void sendLoopTime(int ltimer) {
	char strsend[8] = "T ";
	char strtemp[6];
	sprintf (strtemp, "%5i", ltimer);
	strcat(strsend, strtemp);
	Udp.beginPacket(Udp.remoteIP(), 51432);
	Udp.write(strsend);
	Udp.endPacket();
}
byte BusInit( byte bus, byte addr[][8], OneWire dss ) {
	byte i, n, j = 0, k = 0;
	byte addre[8];
	char add[3], tr1[54];
	if (!dss.reset()) {
		strcpy(tr1, "Ardu3: Bus 0 reset failed!");
		tr1[11] = '0' + bus;
		sendString(tr1);
		strcpy(tr1, "Ardu3: No sensors found on bus 0");
		tr1[31] = '0' + bus;
		sendString(tr1);
	}
	else {
		strcpy(tr1, "Ardu3: Bus 0 reset OK");
		tr1[11] = '0' + bus;								// replacing chars does not work with *t = " "
		sendString(tr1);
		while (j == 0) {
			if (!dss.search(addre)) {
				dss.reset_search();
				for (n = 0; n < k; n++) {
					strcpy(tr1, "Ardu3: Bus 0 sensor 0 code: ");
					tr1[11] = '0' + bus;
					tr1[20] = '0' + n;
					for( i = 0; i < 8; i++) {
						sprintf(add, "%2x", addr[n][i]);
						strcat( tr1, add);
						strcat( tr1, " ");
					}
					sendString(tr1);
				}
				strcpy(tr1, "Ardu3: No more sensors on bus 0 ");
				tr1[30] = '0' + bus;
				sendString(tr1);
				j=1;
			}
			else {
				for( i = 0; i < 8; i++)
					addr[k][i] = addre[i];
				k = k + 1;
				dss.reset();
				if ( OneWire::crc8 ( addre, 7) != addre[7]) {
					strcpy(tr1, "Ardu3: CRC is not valid!");
					sendString(tr1);
					return 0;
				}
				if ( addre[0] != 0x28) {
					strcpy(tr1, "Ardu3: Device is not a DS18B20 family device.");
					sendString(tr1);
					return 0;
				}
			}
		}
	}
	return k;
}
byte RdTemp( byte addr[8], OneWire dss) {			// read one sensor
	byte m1;
	dss.reset();									// the sequence is: 1) reset 2) ROM command 3) function command
	dss.select(addr);								// ROM command = match ROM = address
	dss.write(0xBE);				 				// function command = read scratchpad
	for ( m1 = 0; m1 < 9; m1++)						// read all 9 bytes for crc check
		temp[m1] = dss.read();
	if ( OneWire::crc8 ( temp, 8) != temp[8])
		return 1;
	else return 0;
}
void wh() {									// int routine detects 90 ms 0-pulses from the kWh meter
	byte n1 = 0;
	volatile byte ival = 0;
	while (n1 < 200)						// wait about 100 us
		n1 += 1;
	for (n1 = 0; n1 < 200; n1++)
		ival = ival | digitalRead(intpin);	// check that the zero pulse persists
	if (ival == 0 )
		tint = millis();					// time between two consecutive interrupts used to calculate average power for that period
}
void loop(void) {
	byte addr[maxbus][8][8]; 				// max 8 sensors per bus, each has 8 bytes
	unsigned long tintp = 0;				// previous interrupt time [ms], (initialize to x s to remove spurious INTs)
	unsigned int tinth, tintl;
	unsigned int rounds, roundsp = 0;		// fan rounds, 16 bit
	unsigned int sent_mess_count = 0;		// count the number of sent temp mess
	unsigned long tp = 0, tc = 0;			// millisecond counters for 1 s tick
	unsigned int i = 0, ircount = 0, rpmcount = 0, testint = 4, freeram;
	int tmm = 60, tm = 60;						// default meas period 60 s
	int firstloop = 0, tloop, diff, diffp = 0, rsum = 0;
	int tloopmax = 0, tloophigh = 0, rpmmode = 0;
	int wait = 1000, fani = 1;
	int sendsecondtimer = 0, sendmaxtimer = 0, sendhightimer = 0;
	byte numsensor[maxbus];					// number of sensors discovered on each bus
	byte erro, n, dosearch = 0, firstmess = 0, j1, j2, sendrounds = 0, testread = 0, testreadhex = 0, hptempavemode = 1;
	byte busok[maxbus] = {0, 0};
	float tempf[2][7], tres;
	char tempreadings[] = "E300b0:00b1:00";
	char fanip[3] = "01", *aves;
	char tinl[5], tinh[5], th[3];
	char strtemp1[11], fanis[3], sendudp[54];
	char stud[5] = "0000";
	char sennum[] = "S30";								// number of temp sensors detected
	String stc2;
	tp = millis();
	while (1) {
		int packetSize = Udp.parsePacket();				// send a mess after boot to load remote IP and MAC address
		if (packetSize) {
//			IPAddress remote = Udp.remoteIP();			// MAC recovery, provides dynamic IP address
			firstmess = 1;
			Udp.read(packetBuffer, 64);
			if (( packetBuffer[0] == 'A') && ( packetBuffer[1] == '3')) {
			if (packetBuffer[2] == 'C') {				// RPi requests count of sent temp messages
				strcpy(sendudp, "Ardu3 sent temp messages ");
				sprintf (strtemp1, "%5u", sent_mess_count);
				strcat(sendudp, strtemp1);
				sendString(sendudp);
			}
			else if (packetBuffer[2] == 'D') {			// for recovery of MAC if reset
				strcpy(sendudp, "R3");
				sendString(sendudp);
			}
			else if (packetBuffer[2] == 'F') {			// bytes T1, T2, Fan, Mode to Toshiba
				strcpy(sendudp, "Ardu3 Toshiba IR command ");
				sendString(sendudp);
				ircount += 1;
				convert();						// to Toshiba format
				irsend.enableIROut(38);			// turn on the 38 kHz "carrier"
				sendToshiba();					// Toshiba IR sequence
				sendToshiba();
			}
			else if (packetBuffer[2] == 'G') {			// RPi requests count of rx IR messages
				strcpy(sendudp, "Ardu3 rx IR messages ");
				sprintf (strtemp1, "%5i", ircount);
				strcat(sendudp, strtemp1);
				sendString(sendudp);
			}
			else if (packetBuffer[2] == 'I') {			// set meas period, bytes 1000s, 100s, 10s, 1s
				for (j1 = 0; j1 < 4; j1++)
					stud[j1] = packetBuffer[j1 + 3];
				tmm = atoi(stud);						// period ~ 0010 .... 9999 s
				strcpy(sendudp, "Ardu3: Time interval ");	// send back for check
				sprintf (strtemp1, "%4i", tmm);			// convert int to string
				strcat(sendudp, strtemp1);
				sendString(sendudp);
			}
			else if (packetBuffer[2] == 'K') {			// enable sending of unfiltered rpm TCNT1 values
				if (packetBuffer[3] == 'O')
					sendrounds = 1;
				else sendrounds = 0;
			}
			else if (packetBuffer[2] == 'L') {			// command to turn room leds on/off
				strcpy(sendudp, "Ardu3 room leds ");
				sendString(sendudp);
				if (packetBuffer[3] == '0')
					digitalWrite (4, LOW);
				else if (packetBuffer[3] == '1')
					digitalWrite (4, HIGH);
				else {
					strcpy(sendudp, "Ardu3: Command error");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'R') {			// at boot RPi resets the cycle
				strcpy(sendudp, "Ardu3 reset ");
				sendString(sendudp);
				i = 0;
				dosearch = 0;							// force sensor detection
				tp = tp - 1000;
				sent_mess_count = 0;
			}
			else if (packetBuffer[2] == 'S') {			// set loop timer reporting
				strcpy(sendudp, "Ardu3 loop timer ");
				sendString(sendudp);
				if (packetBuffer[3] == '0' && packetBuffer[4] == 'O')	//
					sendsecondtimer = 1;				// 1 s value
				else if (packetBuffer[3] == '0' && packetBuffer[4] == 'F')
					sendsecondtimer = 0;
				else if (packetBuffer[3] == '1' && packetBuffer[4] == 'O')
					sendmaxtimer = 1;				// 60 s value
				else if (packetBuffer[3] == '1' && packetBuffer[4] == 'F')
					sendmaxtimer = 0;
				else if (packetBuffer[3] == '2' && packetBuffer[4] == 'O')
					sendhightimer = 1;				// cleared when sent
				else if (packetBuffer[3] == '2' && packetBuffer[4] == 'F')
					tloophigh = 0;						// clear max value
				else {
					strcpy(sendudp, "Ardu3: Command error");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'T') {			// test sensors
				if (packetBuffer[3] == 'L'){			// list all
					for (j1 = 0; j1 < maxbus; j1++) {
						for (n = 0; n < numsensor[j1]; n++) {
							strcpy (sendudp, "Ardu3: Bus 0 sensor 0 code: ");
							sendudp[11] = '0' + j1;
							sendudp[20] = '0' + n;
							for ( i = 0; i < 8; i++) {
								sprintf(stud, "%2x", addr[j1][n][i]);
								strcat( sendudp, stud);
								strcat( sendudp, " ");
							}
							sendString(sendudp);
						}
					}
				}
				else if (packetBuffer[3] == 'M'){		// test one temp sensor
					testread = 1;
					if (hptempavemode == 0){
						if ( i > 3  &&  i < 59 )
							testint = i + 1;
						else
							testint = 4;
					}
					else if (hptempavemode == 1){
						if ( i%10 > 3  &&  i%10 < 8 )
							testint = i + 1;
						else if ( i%10 < 4 )
							testint = i + 4;
						else if ( i%10 > 7  && i < 58 )
							testint = i + 6;
						else if ( i > 57 )
							testint = 4;
					}
					if (packetBuffer[4] == 'M')
						testreadhex = 0;
					else if (packetBuffer[4] == 'H') 	// print all 9 bytes in hex
						testreadhex = 1;
					else {
						strcpy(sendudp, "Ardu3: Command error");
						sendString(sendudp);
					}
				}
				else if (packetBuffer[3] == 'R'){		// test amount of free ram A3TR
					freeram = freeMemory();
					strcpy (sendudp, "Ardu3: Free RAM:");
					sprintf (strtemp1, "%6i", freeram);
					strcat(sendudp, strtemp1);
					sendString(sendudp);
				}	
				else {
					strcpy(sendudp, "Ardu3: Command error");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'U') {			// rpm reporting mode
				if (packetBuffer[3] == 'O') {			// report all
					rpmmode = 1;
					strcpy(sendudp, "Ardu3 rpmmode all ");
					sendString(sendudp);
				}
				else rpmmode = 0;						// report only changes > 2%
			}
			else if (packetBuffer[2] == 'V') {			// internal/external temp sens resistor
				if (packetBuffer[3] == 'E') {
					strcpy(sendudp, "Ardu3 temp sensor external NTC ");
					sendString(sendudp);
					digitalWrite(14, LOW);
					digitalWrite(15, LOW);
					digitalWrite(14, HIGH);				// bistable relay
					delay(8);							// 2 ms tested enough
					digitalWrite(14, LOW);
				}
				else if (packetBuffer[3] == 'I') {
					strcpy(sendudp, "Ardu3 temp sensor internal NTC ");
					sendString(sendudp);
					digitalWrite(14, LOW);
					digitalWrite(15, LOW);
					digitalWrite(15, HIGH);
					delay(8);
					digitalWrite(15, LOW);
				}
				else {
					strcpy(sendudp, "Ardu3: Command error");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'W') {			// HP temp averaging mode
				if (packetBuffer[3] == 'O') {			// measure temps once per 10 s and report average
					hptempavemode = 1;
					strcpy(sendudp, "Ardu3 temp averaging mode on ");
					sendString(sendudp);
				}
				else {
					hptempavemode = 0;					// measure and report temps once per minute
					strcpy(sendudp, "Ardu3 temp averaging mode off ");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'X') {			// tune hp's TA temp resistor with resistor R0/1
				if (packetBuffer[3] == '0' && packetBuffer[4] == 'O'){	// R0 ON
					digitalWrite (6, HIGH);
					strcpy(sendudp, "Ardu3 resistor 0 ON ");
					sendString(sendudp);
				}
				else if (packetBuffer[3] == '0' && packetBuffer[4] == 'F'){
					digitalWrite (6, LOW);
					strcpy(sendudp, "Ardu3 resistor 0 OFF ");
					sendString(sendudp);
				}
				else if (packetBuffer[3] == '1' && packetBuffer[4] == 'O'){
					digitalWrite (7, HIGH);
					strcpy(sendudp, "Ardu3 resistor 1 ON ");
					sendString(sendudp);
				}
				else if (packetBuffer[3] == '1' && packetBuffer[4] == 'F'){
					digitalWrite (7, LOW);
					strcpy(sendudp, "Ardu3 resistor 1 OFF ");
					sendString(sendudp);
				}
				else {
					strcpy(sendudp, "Ardu3: Command error");
					sendString(sendudp);
				}
			}
			else if (packetBuffer[2] == 'Z') {			// fan integrating period
				for (j1 = 0; j1 < 2; j1++)
					fanip[j1] = packetBuffer[j1 + 3];
				fani = atoi(fanip);						// period  1/2/5/10 s
				strcpy(sendudp, "Ardu3: Fan integrating period ");	// send back for check
				sprintf (fanis, "%2i", fani);		// convert int to string
				strcat(sendudp, fanis);
				sendString(sendudp);
			}
			else {
				strcpy(sendudp, "Ardu3: Command error");
				sendString(sendudp);
			}
			}
		}
		if ( dosearch == 0 && firstmess == 1 ){
			dosearch = 1;
			n = 0;
			for (j1 = 0; j1 < maxbus; j1++) {		// search sensors once after startup
				numsensor[j1] = BusInit (j1, addr[j1], dss[j1]); // returns the number of sensors found on bus[i]
				n += numsensor[j1];
			}
			sennum[2] = '0' + n;
			sendString(sennum);
		}
		if ( firstloop == 1 ) {
			firstloop = 0;
			tloop = millis() - tp;
			if (sendsecondtimer == 1)
				sendLoopTime(tloop);
			if (tloopmax < tloop)
				tloopmax = tloop;
			if (tloophigh < tloopmax)
				tloophigh = tloopmax;
			if (i == 0) {
				if (sendmaxtimer == 1)
					sendLoopTime(tloopmax);
				tloopmax = 0;						// clear every 60 s
			}
			if (sendhightimer == 1) {
				sendhightimer = 0;					// one shot
				sendLoopTime(tloophigh);
			}
		}
		tc = millis();									// millis timer is said to be roll-over proof when used this way
		if ((( tc - tp ) >= wait) && firstmess == 1){	// 1 s passed and has retrieved MAC
			rounds = TCNT1;								// counts indoor unit's fan pulses. COULD THIS RETURN GIBBERISH?
			if (sendrounds == 1) {						// 12 pulses per round
				strcpy(sendudp, "Ardu3 TCNT1 ");
//				sprintf (strtemp1, "%5i", rounds);		// PRINTS NEGATIVE VALUES WHEN > 32767
				stc2 = String(rounds, DEC);					// 
				stc2.toCharArray(strtemp1, 6);
				strcat(sendudp, strtemp1);
				sendString(sendudp);
			}
			tp = tc;
			i += 1;										// loop counter
			firstloop = 1;
			if (rounds >= roundsp) 
				diff = rounds - roundsp;
			else 
				diff = rounds + (65536 - roundsp);		// roll over
			roundsp = rounds;
			if (rpmmode == 1)
				rsum += diff;
			if (rpmmode == 0) {							// report only changes > 2 %
				rpmcount += 1;
				if ((diff > (1.02 * diffp)) || (diff < (0.98 * diffp))) {
					diffp = diff;
					strcpy(sendudp, "U ");
					sprintf (strtemp1, "%4i", diff);
//					sprintf (strtemp1, "%d", diff);
					strcat(sendudp, strtemp1);
					sendString(sendudp);
				}
				else {									// report value every 5 min even if no > 2 % changes
					if (rpmcount >= 300) {
						rpmcount = 0;
						strcpy(sendudp, "U ");
						sprintf (strtemp1, "%4i", diff);
//						sprintf (strtemp1, "%d", diff);
						strcat(sendudp, strtemp1);
						sendString(sendudp);
					}
				}
			}
			if (i % fani == 0 && rpmmode == 1) {		// 12 pulses per round
				strcpy(sendudp, "Z ");
				sprintf (strtemp1, "%4i", rsum);
//				sprintf (strtemp1, "%d", rsum);
				strcat(sendudp, strtemp1);
				sendString(sendudp);
				rsum = 0;
			}
			if ((tint-tintp) > 0) {						// if INT occurred
				strcpy(sendudp, "Int ms");				// WHEN timer rolls over, nothing sent! Could correct this.
				tintp = tint;
				tintl = tint & 0x0000ffff;
				tinth = (tint >> 16) & 0x0000ffff;
				sprintf ( tinl, "%4x", tintl );			// convert 16 bit int to string
				sprintf ( tinh, "%4x", tinth );			// 32 bit conversion does not work
				strcat(sendudp, tinh);					// send exactly 8 chars
				strcat(sendudp, tinl);
				sendString(sendudp);
			}
			if ((i%10 == 1 && hptempavemode == 1) || (i == 1 && hptempavemode == 0)) {	// start temperature conversion
				for (j1 = 0; j1 < maxbus; j1++) {		// on all buses
					if (numsensor[j1] > 0)				// if bus reset did not fail (= no sensors)
						busok[j1] = StartConversion (j1, 0, dss[j1]);// conversion takes about 750 ms, all sensors in parallel
				}
			}
			if (i == 2 && hptempavemode == 0) {			// read all sensors and send results
				for (j1 = 0; j1 < maxbus; j1++) {		// j1 = bus number
					if (busok[j1] == 1) {
						for (j2 = 0; j2 < numsensor[j1]; j2++){		// j2 = sensor number
							erro = RdTemp (addr[j1][j2], dss[j1]); 	// read one DS18B20
							if (erro == 1) {			// crc error
								strcpy(sendudp, "Ardu3: CRC is not valid!");
								sendString(sendudp);
							}
							else {
								tempreadings[2] = '0' + j1;
								tempreadings[3] = '0' + j2;
								sprintf(th, "%2x", temp[0]);
								tempreadings[7] = th[0];
								tempreadings[8] = th[1];
								sprintf(th, "%2x", temp[1]);
								tempreadings[12] = th[0];
								tempreadings[13] = th[1];
								sendString(tempreadings);
								sent_mess_count += 1;
							}
						}
					}
					else {								// if a bus fails after init, this keeps output printing
						for (j2 = 0; j2 < numsensor[j1]; j2++) {
							tempreadings[2] = '0' + j1;
							tempreadings[3] = '0' + j2;
							tempreadings[7] = '9';		// send dummy value +25 C (0x0190)
							tempreadings[8] = '0';
							tempreadings[12] = '0';
							tempreadings[13] = '1';
							sendString(tempreadings);
							sent_mess_count += 1;
						}
					}
				}
			}
			if (i%10 == 2 && hptempavemode == 1) {		// read all sensors every 10 s and average results
				for (j1 = 0; j1 < maxbus; j1++) {		// j1 = bus number
					if (busok[j1] == 1) {
						for (j2 = 0; j2 < numsensor[j1]; j2++){		// j2 = sensor number
							erro = RdTemp (addr[j1][j2], dss[j1]); 	// read one DS18B20
							if (erro == 1) {			// crc error
								strcpy(sendudp, "Ardu3: CRC is not valid!");
								sendString(sendudp);
							}
							else {
								tres = hextodec();
								tempf[j1][j2] = tempf[j1][j2] + tres;
							}
						}
					}
					else {			
						for (j2 = 0; j2 < numsensor[j1]; j2++)
							tempf[j1][j2] = tempf[j1][j2] + 25.0;
					}
				}
			}
			if (i == 53 && hptempavemode == 1) {		// send average values every minute
				for (j1 = 0; j1 < maxbus; j1++) {
					for (j2 = 0; j2 < numsensor[j1]; j2++){
						tres = tempf[j1][j2] / 6.0;
						tempf[j1][j2] = 0.0;
						aves = ftos3(tres, 4);
						strcpy(sendudp, "F300 ");
						sendudp[2] = '0' + j1;
						sendudp[3] = '0' + j2;
						strcat(sendudp, aves);
						sendString(sendudp);
					}
				}
			}
			if (( i == testint ) && ( testread == 1 )){	// test read selected temp sensor
				j1 = packetBuffer[5] - '0';				// j1 not used by others in between
				j2 = packetBuffer[6] - '0';				// sensor
				dss[j1].reset();
				dss[j1].select(addr[j1][j2]);		   	// ROM command: match ROM = address
				dss[j1].write(0x44, 0);					// convert temp (in parasite mode pow = 1, in +5V mode pow = 0)
			}
			if (( i == (testint + 1)) && ( testread == 1 )){
				testread = 0;
				if ( testreadhex == 0) {				// temp decimal read
					erro = RdTemp (addr[j1][j2], dss[j1]); 	// read one DS18B20
					if (erro == 1){
						strcpy(sendudp, "CRC error temp");
						sendString(sendudp);
					}
					else {
						strcpy( sendudp, "A0S0b0:00b1:00" );	// RPi just prints mess with leading 'A'
						sendudp[1] = '0' + j1;
						sendudp[3] = '0' + j2;
						sprintf(th, "%2x", temp[0]);
						sendudp[7] = th[0];
						sendudp[8] = th[1];
						sprintf(th, "%2x", temp[1]);
						sendudp[12] = th[0];
						sendudp[13] = th[1];
						sendString(sendudp);
					}
				}
				else {									// hex read 9 bytes
					erro = RdTemp (addr[j1][j2], dss[j1]);
					if (erro == 1){
						strcpy(sendudp, "CRC error temp");
						sendString(sendudp);
					}
					else {
						strcpy( sendudp, "A0S0 00 00 00 00 00 00 00 00 00" );
						sendudp[1] = '0' + j1;
						sendudp[3] = '0' + j2;
						for (n = 0; n < 9; n++) {
							sprintf(th, "%2x", temp[n]);
							sendudp[5 + 3 * n ] = th[0];
							sendudp[6 + 3 * n ] = th[1];
						}
						sendString(sendudp);
					}
				}
			}
			if (i == tm){								// last loop per tm
				i = 0;
				tm = tmm;
			}
		}
	}
}
