blob: 10a59ebeace838e43ad79f14fbee3b75b822602d [file] [log] [blame]
// Copyright 2024 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.
#include "message_spi.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <format>
namespace google
{
namespace hoth
{
MessageSPI::MessageSPI(const std::string& path, uint32_t mailbox_addr,
google::hoth::LibHothSpiDevIntf* libhoth_spi, const internal::Sys* sys) :
mailbox_addr(mailbox_addr),
dev(nullptr),
libhoth_spi(libhoth_spi),
sys(sys)
{
struct libhoth_spi_device_init_options opts = {
.path = &path[0],
.mailbox = mailbox_addr,
.bits = 0,
.mode = 0,
.speed = 0,
.atomic = 0,
};
if (libhoth_spi->open(&opts, &dev) != LIBHOTH_OK) {
throw internal::errnoException(
std::format("Error opening Hoth interface "));
}
if (dev == nullptr) {
throw internal::errnoException(
std::format("Error opening Hoth interface \"{}\"", path));
}
}
MessageSPI::~MessageSPI()
{
if (dev != nullptr)
{
libhoth_spi->close(dev);
}
}
void MessageSPI::send(const uint8_t* buf, size_t size, size_t seek)
{
if (seek > size) {
return;
}
ssize_t ret = -1;
do
{
//ret = dev->send(fd, buf, size);
ret = libhoth_spi->send(dev, buf+seek, size);
// Retry if interrupted
} while (ret < 0 && errno == EINTR);
if (ret < 0)
{
throw internal::errnoException("Error writing to Hoth interface");
}
if (static_cast<size_t>(ret) != LIBHOTH_OK)
{
// Fail on incomplete writes because they can confuse Hoth
throw std::runtime_error(std::format(
"Tried to send message of size {} but could only send {} bytes",
size, ret));
}
}
void MessageSPI::recv(uint8_t* buf, size_t size, size_t seek)
{
static uint8_t spidev_buf[LIBHOTH_MAILBOX_SIZE];
static size_t spidev_buf_sz = 0;
if (size + seek > LIBHOTH_MAILBOX_SIZE)
{
return;
}
if (spidev_buf_sz > 0)
{
memcpy(buf, spidev_buf+seek, size);
spidev_buf_sz = 0;
return;
}
read_spidev:
auto ret = libhoth_spi->recv(dev, spidev_buf, LIBHOTH_MAILBOX_SIZE, &spidev_buf_sz, 0);
if (ret < 0)
{
if (errno == EINTR)
{
goto read_spidev; // interrupted; try again
}
throw internal::errnoException("Error reading from Hoth interface");
}
if (spidev_buf_sz == 0)
{
// EOF hit
throw std::runtime_error("Hit EOF while expecting data");
}
memcpy(buf, spidev_buf, size);
}
} // namespace hoth
} // namespace google