/*
 * OneWire.cpp
 *
 *  Created on: Feb 28, 2018
 *      Author: sebastian
 */

#include "OneWire.h"
/*
 * timings in us from
 * https://www.maximintegrated.com/en/app-notes/index.mvp/id/126
 */
uint16_t OWtiming[] = { 6, 64, 60, 10, 9, 55, 0, 480, 70, 410 };

/**
 * Initializes the 1-Wire communication
 */

void OneWire_init() {
	pinMode(OW_PIN, OUTPUT);
	//pullUpDnControl(OW_PIN, PUD_UP); the pull up is already on board
}

/**
 * Writes one byte on the 1-Wire Bus
 */

void OW_writeByte(uint8_t byte) {
	uint8_t loop;
	// Loop to write each bit in the byte, LS-bit first
	for (loop = 0; loop < 8; loop++) {
		OW_writeBit(byte & 0x01);
		// shift the data byte for the next bit
		byte >>= 1;
	}
}

/**
 * Reads a full byte from the 1-Wire Bus
 */

uint8_t OW_readByte(void) {
	uint8_t loop, result = 0;
	for (loop = 0; loop < 8; loop++) {
		// shift the result to get it ready for the next bit
		result >>= 1;
		// if result is one, then set MS bit
		if (OW_readBit())
			result |= 0x80;
	}
	return result;
}

/**
 * Simultaneous write and read from the 1-Wire Bus
 * OW_touchByte(0xFF) is equivalent to OW_readByte()
 * and OW_touchByte(data) is equivalent to OW_writeByte(data)
 */

uint8_t OW_touchByte(uint8_t data) {
	uint8_t loop, result = 0;
	for (loop = 0; loop < 8; loop++) {
		// shift the result to get it ready for the next bit
		result >>= 1;

		// If sending a '1' then read a bit else write a '0'
		if (data & 0x01) {
			if (OW_readBit())
				result |= 0x80;
		} else
			OW_writeBit(0);

		// shift the data byte for the next bit
		data >>= 1;
	}
	return result;
}

/**
 * function which sends and receives a block of data on the 1-Wire Bus
 */

void OW_block(uint8_t *data, uint8_t data_len) {
	int loop;
	for (loop = 0; loop < data_len; loop++) {
		OW_touchByte(data[loop]);
	}
}

/**
 * Writes one bit on the 1-Wire Bus
 */

void OW_writeBit(uint8_t bit) {
	if (bit) { //1
		digitalWrite(OW_PIN, LOW);
		delayMicroseconds(OWtiming[0]);
		digitalWrite(OW_PIN, HIGH);
		delayMicroseconds(OWtiming[1]);
	} else {
		digitalWrite(OW_PIN, LOW);
		delayMicroseconds(OWtiming[2]);
		digitalWrite(OW_PIN, HIGH);
		delayMicroseconds(OWtiming[3]);
	}
}

/**
 * Reads one bit from the 1-Wire Bus and returns it
 */

uint8_t OW_readBit(void) {
	digitalWrite(OW_PIN, LOW);
	delayMicroseconds(OWtiming[0]);
	digitalWrite(OW_PIN, HIGH);
	delayMicroseconds(OWtiming[4]);
	pinMode(OW_PIN, INPUT);
	uint8_t value = digitalRead(OW_PIN);
	delayMicroseconds(OWtiming[5]);
	pinMode(OW_PIN, OUTPUT);
	return value;
}

/**
 * Performs a Reset on the 1-Wire Bus and returns either 1 or 0:
 * 1: if no device is present and 0 if device(s) are present
 */

uint8_t OW_reset() {
	delayMicroseconds(OWtiming[6]);
	digitalWrite(OW_PIN, LOW);
	delayMicroseconds(OWtiming[7]);
	digitalWrite(OW_PIN, HIGH);
	delayMicroseconds(OWtiming[8]);
	pinMode(OW_PIN, INPUT);
	uint8_t value = digitalRead(OW_PIN);
	delayMicroseconds(OWtiming[9]);
	pinMode(OW_PIN, OUTPUT);
	return value;
}
