summaryrefslogtreecommitdiff
path: root/minion/src/temperature.cpp
blob: 46c6300cbb00cd49ad7a96b9a9f293e221eb0dbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "temperature.hpp"

#include <Arduino.h>

TemperatureSensor::TemperatureSensor(uint8_t pin) noexcept : _pin(pin)
{
	pinMode(_pin, OUTPUT);
}

auto TemperatureSensor::read_temperature() noexcept -> TemperatureSensorStatus
{
	// Send start signal and wait
	digitalWrite(_pin, LOW);
	delay(TemperatureSensorTiming::START_SIGNAL_TIME_MILLIS);

	// Pull up and wait for response
	digitalWrite(_pin, HIGH);
	delayMicroseconds(TemperatureSensorTiming::RESPONSE_SIGNAL_WAIT_TIME_MICROS);

	pinMode(_pin, INPUT);

	// The sensor sends a LOW signal and keeps it for 80us
	if (!_wait_read(LOW, TemperatureSensorTiming::RESPONSE_SIGNAL_TIME_MICROS))
	{
		_restore_pin();
		return TemperatureSensorStatus::LOW_RESPONSE_SIGNAL_TIMEOUT;
	}

	// The sensor sends a HIGH signal and keeps it for 80us
	if (!_wait_read(HIGH, TemperatureSensorTiming::RESPONSE_SIGNAL_TIME_MICROS))
	{
		_restore_pin();
		return TemperatureSensorStatus::HIGH_RESPONSE_SIGNAL_TIMEOUT;
	}

	uint8_t data_bytes[TEMPERATURE_SENSOR_RESPONSE_DATA_BYTE_CNT] = { 0U,
																	  0U,
																	  0U,
																	  0U,
																	  0U };

	uint8_t bit_index = BITS_IN_BYTE - 1U;
	uint8_t byte_index = 0U;

	for (uint16_t index = 0U;
		 index < (BITS_IN_BYTE * TEMPERATURE_SENSOR_RESPONSE_DATA_BYTE_CNT);
		 index++)
	{
		// Wait for the start to transmit signal
		if (!_wait_read(
				LOW,
				TemperatureSensorTiming::START_TO_TRANSMIT_SIGNAL_TIME_MICROS + 5U
			))
		{
			_restore_pin();
			return TemperatureSensorStatus::START_TO_TRANSMIT_SIGNAL_TIMEOUT;
		}

		const auto start_time = micros();

		if (!_wait_read(HIGH, TemperatureSensorTiming::DATA_TRANSMIT_TIMEOUT_MICROS))
		{
			_restore_pin();
			return TemperatureSensorStatus::DATA_TRANSMIT_TIMEOUT;
		}

		// A voltage length greater than 40 means the bit is a 1
		if ((micros() - start_time) > 40U)
		{
			data_bytes[byte_index] |= static_cast<uint8_t>(1U << bit_index);
		}

		// Continue to the next byte if it's the last bit
		if (bit_index == 0U)
		{
			// Restart at the MSB
			bit_index = BITS_IN_BYTE - 1U;

			byte_index++;
			continue;
		}

		bit_index--;
	}

	_restore_pin();

	_temperature = data_bytes[2];

	auto sum = data_bytes[0] + data_bytes[2];

	if (data_bytes[4] != sum)
	{
		return TemperatureSensorStatus::CHECKSUM_ERROR;
	}

	return TemperatureSensorStatus::OK;
}

auto TemperatureSensor::temperature() const noexcept -> uint8_t
{
	return _temperature;
}

// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
auto TemperatureSensor::_wait_read(uint8_t level, size_t timeout_micros) noexcept -> bool
{
	const auto start_time = micros();

	while (digitalRead(_pin) == level)
	{
		if ((start_time + timeout_micros) < micros())
		{
			return false;
		}
	}

	return true;
}

void TemperatureSensor::_restore_pin() noexcept
{
	pinMode(_pin, OUTPUT);
	digitalWrite(_pin, HIGH);
}