#include "onewire.h"

uint8_t OW_SEARCH_BUFFER[OW_DEVICE_COUNT][8];

/* DS2482 DRIVER **************************************************************************************************************************************/
uint8_t ds2482_detect(I2C_HandleTypeDef *hi2c) { 

		if(!ds2482_reset(hi2c) || !ds2482_write_config(hi2c, DS2482_CFG_APU)){
			return 0;
		}
		else{
			return 1;
		}

}

uint8_t ds2482_reset(I2C_HandleTypeDef *hi2c){
	uint8_t DATA = DS2482_CMD_DRST;	
	uint8_t RxBUFFER; 

	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, &DATA, 1, 1) == HAL_OK){
		if(HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1) == HAL_OK){
		return ((RxBUFFER & 0xf7) == 0x10);
		//return 1;
		}
	return 0;
  }	
}	

uint8_t ds2482_write_config(I2C_HandleTypeDef *hi2c, uint8_t config)
{
	uint8_t tmp; 
	uint8_t RxBUFFER; 
	
	tmp = (uint8_t)(config | (~config << 4));
	
	uint8_t CFG[] =  {DS2482_CMD_WCFG,tmp};
	
		if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG, 2, 1) == HAL_OK){
		if(HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1) == HAL_OK){
			
				if(config != RxBUFFER) { 
				  ds2482_reset(hi2c);  
				}
				else{				
					return 1;
				}
		}
  }	
		return 0;

}	

/* OW RESET **************************************************************************************************************************************/
uint8_t OW_Reset(I2C_HandleTypeDef *hi2c) 
{		
  uint8_t DATA = DS2482_CMD_1WRS;	
	uint8_t RxBUFFER; 
	
	uint8_t CFG[] = {DS2482_CMD_SRP, DS2482_READPTR_SR};
	uint8_t poll_count = 0;
		
	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, &DATA, 1, 1) == HAL_OK){
		do { 
			
			HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG, 2, 1);
			HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1);
			
		} while((RxBUFFER & DS2482_STATUS_1WB) && (poll_count++ < POLL_LIMIT));			
	}	
	
	if(poll_count >= POLL_LIMIT) { 
		ds2482_reset(hi2c); 
	return 0; 
	}
	if(RxBUFFER & DS2482_STATUS_PPD){ 
		return 1; 
	}
	else{
		return 0;
	}
}

uint8_t OW_WriteByte(I2C_HandleTypeDef *hi2c, uint8_t SEND_BYTE){	
	
	uint8_t CFG[] =  {DS2482_CMD_1WWB, SEND_BYTE};
	uint8_t CFG2[] =  {DS2482_CMD_SRP, DS2482_READPTR_SR};
	uint8_t poll_count = 0;
	uint8_t RxBUFFER; 
		
	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG, 2, 1) == HAL_OK){
		do { 
			
			HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG2, 2, 1);
			HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1);
			
		} while((RxBUFFER & DS2482_STATUS_1WB) && (poll_count++ < POLL_LIMIT));			
	}	
	
	if(poll_count >= POLL_LIMIT) ds2482_reset(hi2c);	
}


uint8_t OW_TouchBit(I2C_HandleTypeDef *hi2c, uint8_t SEND_BYTE){	
	
	uint8_t CFG[] =  {DS2482_CMD_1WSB, (uint8_t)(SEND_BYTE ? 0x80:0x00)};
	uint8_t CFG2[] =  {DS2482_CMD_SRP, DS2482_READPTR_SR};
	uint8_t poll_count = 0;
	uint8_t RxBUFFER; 
		
	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG, 2, 1) == HAL_OK){
		do { 			
			HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG2, 2, 1);
			HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1);
			
		} while((RxBUFFER & DS2482_STATUS_1WB) && (poll_count++ < POLL_LIMIT));			
	}	
	
	if(poll_count >= POLL_LIMIT){ ds2482_reset(hi2c); return 0; }
	if(RxBUFFER & DS2482_STATUS_SBR) return 1; return 0;
}

uint8_t OW_ReadByte(I2C_HandleTypeDef *hi2c) {
	uint8_t DATA = DS2482_CMD_1WRB;	
	uint8_t RxBUFFER; 
	
	uint8_t CFG[] =  {DS2482_CMD_SRP, DS2482_READPTR_SR};
	uint8_t CFG2[] =  {DS2482_CMD_SRP, DS2482_READPTR_RDR};
	uint8_t poll_count = 0;
		
	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, &DATA, 1, 1) == HAL_OK){
		do { 			
			HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG, 2, 1);
			HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1);
			
		} while((RxBUFFER & DS2482_STATUS_1WB) && (poll_count++ < POLL_LIMIT));		
	}	
	
	if(HAL_I2C_Master_Transmit(hi2c, (uint16_t)DS2482_HW_ADDRESS, CFG2, 2, 1) == HAL_OK){
			HAL_I2C_Master_Receive(hi2c, (uint16_t)DS2482_HW_ADDRESS, &RxBUFFER, 1, 1);
		}
	
 return RxBUFFER;
	
}

void OW_WriteBit(I2C_HandleTypeDef *hi2c, uint8_t SEND_BYTE){OW_TouchBit(hi2c, SEND_BYTE); }

uint8_t OW_ReadBit(I2C_HandleTypeDef *hi2c) {return OW_TouchBit(hi2c, 0x01);}


/* OW PROC **************************************************************************************************************************************/
uint8_t OW_SearchRom(uint8_t diff, uint8_t *id,I2C_HandleTypeDef *hi2c) {
	uint8_t b, i, j, next_diff;

	if(!OW_Reset(hi2c)){
		return OW_PRESENCE_ERR;
	}		// error, no device found <--- early exit!
	
	OW_WriteByte(hi2c, OW_SEARCH_ROM);					// ROM search command
	next_diff = OW_LAST_DEVICE;					// unchanged on last device
	i = OW_ROMCODE_SIZE * 8;
	
	do {
		j = 8;
		do {
			b = OW_ReadBit(hi2c);
			if(OW_ReadBit(hi2c)) { if(b) return OW_DATA_ERR; }
			else { if(!b) if(diff > i || ((*id & 1) && diff != i)) { b = 1; next_diff = i; } }
			OW_WriteBit(hi2c, b);
			*id >>= 1;
			if(b) *id |= 0x80;
			i--;
		} while(--j);
		id++;
	} while(i);
	
	return next_diff;
}

void OW_Search(I2C_HandleTypeDef *hi2c) {	
	uint8_t i, check, count = 0, id[8];

	for(i = 0; i < OW_DEVICE_COUNT; i++) OW_SEARCH_BUFFER[i][0] = 0;
		
	check = OW_SEARCH_FIRST;
	while(check != OW_LAST_DEVICE && count < 64) {
		check = OW_SearchRom(check, &id[0], hi2c);
		if(check == OW_PRESENCE_ERR) { 
			break;
		}
		if(check == OW_DATA_ERR) { 
			break;
		}
		for(i = 0; i < OW_ROMCODE_SIZE; i++) OW_SEARCH_BUFFER[count][i] = id[i];
		count++;						
	}	
}


static void OW_InternCommand(uint8_t command, uint8_t *id, uint8_t reset, I2C_HandleTypeDef *hi2c)
{
	uint8_t i;
		volatile float TDkyb; 
			
	if(reset) OW_Reset(hi2c);
	
	if(id) {
		OW_WriteByte(hi2c, OW_MATCH_ROM);				// to a single device
		i = OW_ROMCODE_SIZE;
		do { OW_WriteByte(hi2c, *id); id++; } while(--i);
	} 
	else OW_WriteByte(hi2c, OW_SKIP_ROM);					// to all devices              
	OW_WriteByte(hi2c, command);
}

void OW_Command(uint8_t command, uint8_t *id, uint8_t reset, I2C_HandleTypeDef *hi2c) {
	
	OW_InternCommand(command, id, reset, hi2c);
}


/* DS18B20 ************************************************************************************************************************************/
float Read_ds18b20(uint8_t *Serial_Number, I2C_HandleTypeDef *hi2c, float T_Old) {
	uint8_t i, Data[8], crc;	
	float T;
	
 	OW_Command(OW_READ_SCRATCHPAD, Serial_Number, 1, hi2c);	
	
		for (i = 0; i < 8; i++){
			Data[i] = OW_ReadByte(hi2c);
		}

		T=((float)Data[1]*256+(float)Data[0])/16;
		if(T>140){T = 0;}
		
		/* Calculate CRC */
	crc = OW_Checksum(Data, 8);
			/* Check if CRC is ok */
	if (crc != Data[8]) {
		/* CRC invalid */
		return 999;
	}
		
//		if (OW_Checksum(Data, 8)){
//			T=((float)Data[1]*256+(float)Data[0])/16;
//			if(T>125){T = 0;}
//		}
//		else{
//			return ERROR;
//		}	
		
	//return (T + T_Old)/2;
	return T;
		
}

void ConvertTemperature_ds18b20(I2C_HandleTypeDef *hi2c)
{ 
  if(OW_Reset(hi2c)){
		OW_WriteByte(hi2c, OW_SKIP_ROM);							
		OW_WriteByte(hi2c, OW_CONVERT_T);	
	}		
}




/* CRC **************************************************************************************************************************************/
uint8_t crc8(uint8_t *data, uint16_t number_of_bytes_in_data) {
	uint8_t  crc;
	uint16_t loop_count;
	uint8_t  bit_counter;
	uint8_t  b;
	uint8_t  feedback_bit;
	crc = CRC8INIT;
	for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) {
		b = data[loop_count];
		bit_counter = 8;
		do {
			feedback_bit = (crc ^ b) & 0x01;
			if (feedback_bit == 0x01) {
				crc = crc ^ CRC8POLY;
			}
			crc = (crc >> 1) & 0x7F;
			if ( feedback_bit == 0x01 ) {
				crc = crc | 0x80;
			}
			b = b >> 1;
			bit_counter--;
		
		} while (bit_counter > 0);
	}
	return crc;
}


uint8_t OW_CRC_Byte(uint8_t crc, uint8_t Data)
{
  uint8_t i;

  crc ^= Data;
  for(i = 0; i < 8; i++)
  {
    if (crc & 0x01)
      crc = (crc >> 1) ^ 0x8C;
    else
      crc >>= 1;
  }

  return crc;
}

//uint8_t OW_Checksum(uint8_t *DataBuf, uint8_t Size)
//{
//	uint8_t  crc;

//  crc = 0;
//  while (Size--)
//  {
//    crc = OW_CRC_Byte(crc, *DataBuf++);
//  }

//  return crc;
//}

uint8_t OW_Checksum(uint8_t *addr, uint8_t len) {
	uint8_t crc = 0, inbyte, i, mix;
	
	while (len--) {
		inbyte = *addr++;
		for (i = 8; i; i--) {
			mix = (crc ^ inbyte) & 0x01;
			crc >>= 1;
			if (mix) {
				crc ^= 0x8C;
			}
			inbyte >>= 1;
		}
	}
	
	/* Return calculated CRC */
	return crc;
}


