// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "pcf8563.h"

#include <fidl/fuchsia.hardware.i2c/cpp/fidl.h>
#include <fidl/fuchsia.hardware.rtc/cpp/fidl.h>
#include <lib/driver/component/cpp/driver_export.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/fit/function.h>
#include <lib/zx/result.h>

#include <cstdint>
#include <memory>
#include <optional>
#include <utility>
#include <vector>

#include "pcf8563-server.h"

namespace fdf {
using namespace fuchsia_driver_framework;
}  // namespace fdf

namespace pcf8563 {

namespace {

namespace fi2c = fuchsia_hardware_i2c;
namespace frtc = fuchsia_hardware_rtc;

uint8_t to_bcd(uint8_t binary) {
  return static_cast<uint8_t>((((binary / 10) << 4) | (binary % 10)));
}

uint8_t from_bcd(uint8_t bcd) { return ((bcd >> 4) * 10) + (bcd & 0xf); }

}  // namespace

zx::result<> RtcDriver::Start() {
  {
    auto result = incoming()->Connect<fi2c::Service::Device>();
    if (result.is_error()) {
      FDF_LOG(ERROR, "Connect(): %s", result.status_string());
      return result.take_error();
    }
    i2c_.Bind(std::move(result.value()));
  }

  server_ = std::make_unique<RtcServer>(this);

  {
    auto result = outgoing()->AddService<frtc::Service>(server_->GetInstanceHandler());
    if (result.is_error()) {
      FDF_LOG(ERROR, "AddService(): %s", result.status_string());
      return result.take_error();
    }
  }

  {
    auto result = CreateDevfsNode();
    if (result.is_error()) {
      FDF_LOG(ERROR, "CreateDevfsNode(): %s", result.status_string());
      return result.take_error();
    }
  }

  return zx::ok();
}

zx::result<frtc::Time> RtcDriver::Read() {
  std::vector<fi2c::Transaction> txns{
      {{.data_transfer = fi2c::DataTransfer::WithWriteData({0x02})}},
      {{.data_transfer = fi2c::DataTransfer::WithReadSize(7)}},
  };

  auto result = i2c_->Transfer({{.transactions = std::move(txns)}});
  if (result.is_error()) {
    FDF_LOG(ERROR, "i2c_.Transfer(): %s", result.error_value().FormatDescription().c_str());
    if (result.error_value().is_framework_error()) {
      return zx::error(ZX_ERR_INTERNAL);
    }
    return zx::error(result.error_value().domain_error());
  }

  // Transfer() returns a vector of byte-vectors, one per read-transfer.
  std::vector<uint8_t> rx_data = result->read_data()[0];

  frtc::Time time{{
      .seconds = from_bcd(rx_data[0] & 0x7f),
      .minutes = from_bcd(rx_data[1] & 0x7f),
      .hours = from_bcd(rx_data[2] & 0x3f),
      .day = from_bcd(rx_data[3] & 0x3f),
      // .weekday unused.
      .month = from_bcd(rx_data[5] & 0x1f),
      .year = static_cast<uint16_t>(((rx_data[5] & 0x80) ? 2000 : 1900) + from_bcd(rx_data[6])),
  }};
  return zx::ok(time);
}

zx::result<> RtcDriver::Write(frtc::Time rtc) {
  int year = rtc.year();

  // The PCF8563 uses 1 BCD-encoded byte for the year (0-99). The century is encoded as the high-bit
  // of the month field whose value represents century_bit ? 2000 : 1900. As a consequence, this
  // chip can only support dates whose year is in the range 1900 through 2099.
  if (year < 1900 || year > 2099) {
    FDF_LOG(ERROR, "year=%d, must be between 1900 and 2099", year);
    return zx::error(ZX_ERR_OUT_OF_RANGE);
  }

  uint8_t century_bit = (year < 2000) ? 0 : 1;
  year -= century_bit ? 2000 : 1900;  // Normalize to a value between 0 and 99.

  std::vector<uint8_t> tx_data = {
      0x02,
      to_bcd(rtc.seconds()),
      to_bcd(rtc.minutes()),
      to_bcd(rtc.hours()),
      to_bcd(rtc.day()),
      0,  // day of week
      static_cast<uint8_t>(century_bit << 7 | to_bcd(rtc.month())),
      to_bcd(static_cast<uint8_t>(year)),
  };

  std::vector<fi2c::Transaction> txns{
      {{.data_transfer = fi2c::DataTransfer::WithWriteData(std::move(tx_data))}},
  };

  auto result = i2c_->Transfer({{.transactions = std::move(txns)}});
  if (result.is_error()) {
    FDF_LOG(ERROR, "i2c_.Transfer(): %s", result.error_value().FormatDescription().c_str());
    if (result.error_value().is_framework_error()) {
      return zx::error(ZX_ERR_INTERNAL);
    }
    return zx::error(result.error_value().domain_error());
  }

  return zx::ok();
}

void RtcDriver::DevfsConnect(fidl::ServerEnd<frtc::Device> req) {
  server_->bindings().AddBinding(dispatcher(), std::move(req), server_.get(),
                                 fidl::kIgnoreBindingClosure);
}

zx::result<> RtcDriver::CreateDevfsNode() {
  auto connector = devfs_connector_.Bind(dispatcher());
  if (connector.is_error()) {
    FDF_LOG(ERROR, "devfs_connector_.Bind(): %s", connector.status_string());
    return connector.take_error();
  }

  fdf::DevfsAddArgs devfs;
  devfs.connector(std::move(connector.value()));
  devfs.class_name("rtc");

  fdf::NodeAddArgs args;
  args.devfs_args(std::move(devfs));
  args.name("rtc");

  // server-end required by AddChild().
  auto controller_eps = fidl::CreateEndpoints<fdf::NodeController>();
  if (controller_eps.is_error()) {
    FDF_LOG(ERROR, "fidl::CreateEndpoints<NodeController>(): %s", controller_eps.status_string());
    return controller_eps.take_error();
  }
  node_controller_.Bind(std::move(controller_eps->client));

  // server-end required by AddChild().
  auto node_eps = fidl::CreateEndpoints<fdf::Node>();
  if (node_eps.is_error()) {
    FDF_LOG(ERROR, "fidl::CreateEndpoints<Node>(): %s", node_eps.status_string());
    return node_eps.take_error();
  }
  node_.Bind(std::move(node_eps->client));

  auto result = fidl::Call(node())->AddChild({{
      .args = std::move(args),
      .controller = std::move(controller_eps->server),
      .node = std::move(node_eps->server),
  }});

  if (result.is_error()) {
    FDF_LOG(ERROR, "AddChild(): %s", result.error_value().FormatDescription().c_str());
    // Node API assumes bespoke error and does not use zx_status_t.
    return zx::error(ZX_ERR_INTERNAL);
  }

  return zx::ok();
}

}  // namespace pcf8563

FUCHSIA_DRIVER_EXPORT(pcf8563::RtcDriver);
