File serial_coroutines.hpp
File List > include > libhal-util > serial_coroutines.hpp
Go to the documentation of this file
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cctype>
#include <cstdint>
#include <optional>
#include <span>
#include <libhal/error.hpp>
#include <libhal/serial.hpp>
#include <libhal/timeout.hpp>
#include <libhal/units.hpp>
#include "as_bytes.hpp"
#include "comparison.hpp"
#include "enum.hpp"
namespace hal {
class skip_past
{
public:
skip_past(serial& p_serial,
std::span<const hal::byte> p_sequence,
size_t p_read_limit = 32)
: m_serial(&p_serial)
, m_sequence(p_sequence)
, m_read_limit(p_read_limit)
{
}
result<work_state> operator()()
{
if (m_search_index == m_sequence.size()) {
return work_state::finished;
}
for (size_t read_limit = 0; read_limit < m_read_limit; read_limit++) {
std::array<hal::byte, 1> buffer;
auto read_result = HAL_CHECK(m_serial->read(buffer));
if (read_result.data.size() != buffer.size()) {
return work_state::in_progress;
}
// Check if the next byte received matches the sequence
if (m_sequence[m_search_index] == read_result.data[0]) {
m_search_index++;
} else { // Otherwise set the search index back to the start.
m_search_index = 0;
}
// Check if the search index is equal to the size of the sequence size
if (m_search_index == m_sequence.size()) {
return work_state::finished;
}
}
return work_state::in_progress;
}
private:
serial* m_serial;
std::span<const hal::byte> m_sequence;
size_t m_read_limit;
size_t m_search_index = 0;
};
class read_into
{
public:
read_into(serial& p_serial,
std::span<hal::byte> p_buffer,
size_t p_read_limit = 32)
: m_serial(&p_serial)
, m_buffer(p_buffer)
, m_read_limit(p_read_limit)
{
}
result<work_state> operator()()
{
for (size_t read_limit = 0; read_limit < m_read_limit; read_limit++) {
if (m_buffer.empty()) {
return work_state::finished;
}
auto read_result = HAL_CHECK(m_serial->read(m_buffer));
// Set the m_buffer to the amount of bytes remaining to be read.
m_buffer = m_buffer.subspan(read_result.data.size());
if (read_result.data.empty()) {
return work_state::in_progress;
}
}
return work_state::in_progress;
}
private:
serial* m_serial;
std::span<hal::byte> m_buffer;
size_t m_read_limit;
};
class read_upto
{
public:
read_upto(serial& p_serial,
std::span<const hal::byte> p_sequence,
std::span<hal::byte> p_buffer,
size_t p_read_limit = 32)
: m_serial(&p_serial)
, m_sequence(p_sequence)
, m_buffer(p_buffer)
, m_read_limit(p_read_limit)
{
}
result<work_state> operator()()
{
static constexpr size_t read_length = 1;
if (m_search_index == m_sequence.size()) {
return work_state::finished;
}
if (m_buffer.empty()) {
return work_state::failed;
}
for (size_t read_limit = 0; read_limit < m_read_limit; read_limit++) {
auto read_result =
HAL_CHECK(m_serial->read(m_buffer.subspan(0, read_length)));
if (read_result.data.size() == 0) {
return work_state::in_progress;
}
// Check if the next byte received matches the sequence
if (m_sequence[m_search_index] == read_result.data[0]) {
m_search_index++;
} else { // Otherwise set the search index back to the start.
m_search_index = 0;
}
// Check if the search index is equal to the size of the sequence size
if (m_search_index == m_sequence.size()) {
return work_state::finished;
}
m_buffer = m_buffer.subspan(read_length);
if (m_buffer.empty()) {
return work_state::failed;
}
}
return work_state::in_progress;
}
private:
serial* m_serial;
std::span<const hal::byte> m_sequence;
std::span<hal::byte> m_buffer;
size_t m_read_limit;
size_t m_search_index = 0;
};
class read_uint32
{
public:
read_uint32(serial& p_serial, size_t p_read_limit = 32)
: m_serial(&p_serial)
, m_read_limit(p_read_limit)
{
}
result<work_state> operator()()
{
if (m_finished) {
return work_state::finished;
}
for (size_t read_limit = 0; read_limit < m_read_limit; read_limit++) {
std::array<hal::byte, 1> buffer;
auto read_result = HAL_CHECK(m_serial->read(buffer));
if (read_result.data.size() != buffer.size()) {
return work_state::in_progress;
}
if (std::isdigit(static_cast<char>(read_result.data[0]))) {
m_integer_value *= 10;
m_integer_value += read_result.data[0] - hal::byte('0');
m_found_digit = true;
} else if (m_found_digit) {
m_finished = true;
return work_state::finished;
}
}
return work_state::in_progress;
}
std::optional<uint32_t> get()
{
if (!m_finished) {
return std::nullopt;
}
return m_integer_value;
}
private:
serial* m_serial;
size_t m_read_limit;
std::uint32_t m_integer_value = 0;
bool m_found_digit = false;
bool m_finished = false;
};
} // namespace hal