From 3ede86caf948d6e989fd056ea4f8d8c588939971 Mon Sep 17 00:00:00 2001 From: HampusM Date: Mon, 16 May 2022 12:44:58 +0200 Subject: feat(minion): add reading temperature sensor --- minion/.clang-tidy | 2 + minion/src/gymnasiearbete.cpp | 47 +++++++++++++-- minion/src/http/response_status.hpp | 1 + minion/src/temperature.cpp | 117 ++++++++++++++++++++++++++++++++++++ minion/src/temperature.hpp | 42 +++++++++++++ 5 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 minion/src/temperature.cpp create mode 100644 minion/src/temperature.hpp diff --git a/minion/.clang-tidy b/minion/.clang-tidy index dacfe3c..9d97431 100644 --- a/minion/.clang-tidy +++ b/minion/.clang-tidy @@ -10,11 +10,13 @@ Checks: ' readability-*, -modernize-avoid-c-arrays, -modernize-deprecated-headers, + -modernize-loop-convert, -cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-no-malloc, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-owning-memory' WarningsAsErrors: '*' HeaderFilterRegex: '\/src\/' diff --git a/minion/src/gymnasiearbete.cpp b/minion/src/gymnasiearbete.cpp index a1f6d51..fada1e2 100644 --- a/minion/src/gymnasiearbete.cpp +++ b/minion/src/gymnasiearbete.cpp @@ -1,6 +1,7 @@ #include "http/request.hpp" #include "http/response_status.hpp" #include "secrets.hpp" +#include "temperature.hpp" #include "wifi_module.hpp" #include @@ -14,10 +15,16 @@ constexpr auto BAUDRATE = 9600U; constexpr auto NETWORK_MODULE_RX_PIN = 13U; constexpr auto NETWORK_MODULE_TX_PIN = 11U; +constexpr auto TEMPERATURE_SENSOR_PIN = 9U; + constexpr auto SECOND_IN_MILLIS = 1000U; +constexpr auto RESPONSE_DATA_MAX_LENGTH = 64U; + auto wifi_module = WiFiModule({ NETWORK_MODULE_RX_PIN, NETWORK_MODULE_TX_PIN }); +auto temperature_sensor = TemperatureSensor(TEMPERATURE_SENSOR_PIN); + void setup() { Serial.begin(BAUDRATE); @@ -102,12 +109,44 @@ void loop() Serial.print("\nData: "); Serial.println(request.data()); - wifi_module.send_response(connection, HTTP_RESPONSE_STATUS_OK, "hello there!"); + const auto temperature_sensor_status = temperature_sensor.read_temperature(); - wifi_module.close_connection(connection); + if (temperature_sensor_status != TemperatureSensorStatus::OK) + { + Serial.print("Error: "); + Serial.println(static_cast(temperature_sensor_status)); - Serial.print("Connection closed: "); - Serial.println(connection.is_closed() ? "true" : "false"); + wifi_module.send_response( + connection, + HTTP_RESPONSE_STATUS_INTERNAL_SERVER_ERROR, + R"({"error": "Internal server error"})" + ); + + wifi_module.close_connection(connection); + + delay(SECOND_IN_MILLIS); + + return; + } + + char response_data[RESPONSE_DATA_MAX_LENGTH] = ""; + + snprintf( + response_data, + RESPONSE_DATA_MAX_LENGTH, + "%u", + temperature_sensor.temperature() + ); + + const auto send_response_ok = + wifi_module.send_response(connection, HTTP_RESPONSE_STATUS_OK, response_data); + + if (!send_response_ok) + { + Serial.println("Failed to send response"); + } + + wifi_module.close_connection(connection); delay(SECOND_IN_MILLIS); } diff --git a/minion/src/http/response_status.hpp b/minion/src/http/response_status.hpp index 577eedd..4db7546 100644 --- a/minion/src/http/response_status.hpp +++ b/minion/src/http/response_status.hpp @@ -1,3 +1,4 @@ #pragma once constexpr auto HTTP_RESPONSE_STATUS_OK = 200U; +constexpr auto HTTP_RESPONSE_STATUS_INTERNAL_SERVER_ERROR = 500U; diff --git a/minion/src/temperature.cpp b/minion/src/temperature.cpp new file mode 100644 index 0000000..1231e24 --- /dev/null +++ b/minion/src/temperature.cpp @@ -0,0 +1,117 @@ +#include "temperature.hpp" + +#include + +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)) + { + return TemperatureSensorStatus::TIMEOUT; + } + + // The sensor sends a HIGH signal and keeps it for 80us + if (!_wait_read(HIGH, TemperatureSensorTiming::RESPONSE_SIGNAL_TIME_MICROS)) + { + return TemperatureSensorStatus::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 + )) + { + return TemperatureSensorStatus::TIMEOUT; + } + + const auto start_time = micros(); + + if (!_wait_read(HIGH, TemperatureSensorTiming::DATA_TRANSMIT_TIMEOUT_MICROS)) + { + return TemperatureSensorStatus::TIMEOUT; + } + + // A voltage length greater than 40 means the bit is a 1 + if ((micros() - start_time) > 40U) + { + data_bytes[byte_index] |= static_cast(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 to initial state + pinMode(_pin, OUTPUT); + digitalWrite(_pin, HIGH); + + _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; +} diff --git a/minion/src/temperature.hpp b/minion/src/temperature.hpp new file mode 100644 index 0000000..dcc213c --- /dev/null +++ b/minion/src/temperature.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +namespace TemperatureSensorTiming +{ + +constexpr auto START_SIGNAL_TIME_MILLIS = 18U; +constexpr auto RESPONSE_SIGNAL_WAIT_TIME_MICROS = 40U; +constexpr auto RESPONSE_SIGNAL_TIME_MICROS = 80U; +constexpr auto START_TO_TRANSMIT_SIGNAL_TIME_MICROS = 50U; +constexpr auto DATA_TRANSMIT_TIMEOUT_MICROS = 80U; + +} // namespace TemperatureSensorTiming + +constexpr auto TEMPERATURE_SENSOR_RESPONSE_DATA_BYTE_CNT = 5U; +constexpr auto BITS_IN_BYTE = 8U; + +enum class TemperatureSensorStatus +{ + OK, + TIMEOUT, + CHECKSUM_ERROR +}; + +class TemperatureSensor +{ +public: + explicit TemperatureSensor(uint8_t pin) noexcept; + + auto read_temperature() noexcept -> TemperatureSensorStatus; + + auto temperature() const noexcept -> uint8_t; + +private: + const uint8_t _pin; + + uint8_t _temperature{}; + + auto _wait_read(uint8_t level, size_t timeout_micros) noexcept -> bool; +}; -- cgit v1.2.3-18-g5258