Skip to content

File serial.hpp

File List > include > libhal-util > serial.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 <cstdio>
#include <span>
#include <string_view>

#include <libhal/error.hpp>
#include <libhal/serial.hpp>
#include <libhal/timeout.hpp>
#include <libhal/units.hpp>

#include "as_bytes.hpp"
#include "comparison.hpp"
#include "math.hpp"

namespace hal {

[[nodiscard]] constexpr auto operator==(const serial::settings& p_lhs,
                                        const serial::settings& p_rhs)
{
  return equals(p_lhs.baud_rate, p_rhs.baud_rate) &&
         p_lhs.parity == p_rhs.parity && p_lhs.stop == p_rhs.stop;
}
[[nodiscard]] inline result<serial::write_t> write_partial(
  serial& p_serial,
  std::span<const hal::byte> p_data_out)
{
  return p_serial.write(p_data_out);
}

[[nodiscard]] inline status write(serial& p_serial,
                                  std::span<const hal::byte> p_data_out)
{
  auto remaining = p_data_out;

  while (remaining.size() != 0) {
    auto write_length = HAL_CHECK(p_serial.write(remaining)).data.size();
    remaining = remaining.subspan(write_length);
  }

  return success();
}

[[nodiscard]] inline status write(serial& p_serial, std::string_view p_data_out)
{
  return write(p_serial, as_bytes(p_data_out));
}

[[nodiscard]] inline result<std::span<hal::byte>>
read(serial& p_serial, std::span<hal::byte> p_data_in, timeout auto p_timeout)
{
  auto remaining = p_data_in;

  while (remaining.size() != 0) {
    auto read_length = HAL_CHECK(p_serial.read(remaining)).data.size();
    remaining = remaining.subspan(read_length);
    HAL_CHECK(p_timeout());
  }

  return p_data_in;
}

template<size_t BytesToRead>
[[nodiscard]] result<std::array<hal::byte, BytesToRead>> read(
  serial& p_serial,
  timeout auto p_timeout)
{
  std::array<hal::byte, BytesToRead> buffer;
  HAL_CHECK(read(p_serial, buffer, p_timeout));
  return buffer;
}

[[nodiscard]] inline result<std::span<hal::byte>> write_then_read(
  serial& p_serial,
  std::span<const hal::byte> p_data_out,
  std::span<hal::byte> p_data_in,
  timeout auto p_timeout)
{
  HAL_CHECK(write_partial(p_serial, p_data_out));
  return read(p_serial, p_data_in, p_timeout);
}

template<size_t BytesToRead>
[[nodiscard]] result<std::array<hal::byte, BytesToRead>> write_then_read(
  serial& p_serial,
  std::span<const hal::byte> p_data_out,
  timeout auto p_timeout)
{
  std::array<hal::byte, BytesToRead> buffer;
  HAL_CHECK(write_then_read(p_serial, p_data_out, buffer, p_timeout));
  return buffer;
}

template<typename DataArray>
void print(serial& p_serial, DataArray&& p_data)
{
  (void)hal::write(p_serial, p_data);
}

template<size_t BufferSize, typename... Parameters>
void print(serial& p_serial, const char* p_format, Parameters... p_parameters)
{
  static_assert(BufferSize > 2);

  std::array<char, BufferSize> buffer{};
  constexpr int unterminated_max_string_size = static_cast<int>(BufferSize) - 1;

  int length =
    std::snprintf(buffer.data(), buffer.size(), p_format, p_parameters...);

  if (length > unterminated_max_string_size) {
    // Print out what was able to be written to the buffer
    length = unterminated_max_string_size;
  }

  (void)hal::write(p_serial, std::string_view(buffer.data(), length));
}
}  // namespace hal