// 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
//
//     https://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

// This file is autogenerated by:
//   cbindgen --config cbindgen.toml src/ffi.rs -o include/rootcanal_rs.h
// Don't modify manually.

struct LinkManager;
struct LinkLayer;

#include <stdint.h>

/// Link Manager callbacks
struct ControllerOps {
  void* user_pointer;
  uint16_t (*get_handle)(void* user, const uint8_t (*address)[6]);
  void (*get_address)(void* user, uint16_t handle, uint8_t (*result)[6]);
  uint64_t (*get_extended_features)(void* user, uint8_t features_page);
  uint64_t (*get_le_features)(void* user);
  uint64_t (*get_le_event_mask)(void* user);
  void (*send_hci_event)(void* user, const uint8_t* data, uintptr_t len);
  void (*send_lmp_packet)(void* user, const uint8_t (*to)[6], const uint8_t* data, uintptr_t len);
  void (*send_llcp_packet)(void* user, uint16_t handle, const uint8_t* data, uintptr_t len);
};

extern "C" {

/// Create a new link manager instance
/// # Arguments
/// * `ops` - Function callbacks required by the link manager
const LinkManager* link_manager_create(ControllerOps ops);

/// Register a new link with a peer inside the link manager
/// # Arguments
/// * `lm` - link manager pointer
/// * `peer` - peer address as array of 6 bytes
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointer
/// - `peer` must be valid for reads for 6 bytes
bool link_manager_add_link(const LinkManager* lm, const uint8_t (*peer)[6]);

/// Unregister a link with a peer inside the link manager
/// Returns true if successful
/// # Arguments
/// * `lm` - link manager pointer
/// * `peer` - peer address as array of 6 bytes
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointer
/// - `peer` must be valid for reads for 6 bytes
bool link_manager_remove_link(const LinkManager* lm, const uint8_t (*peer)[6]);

/// Run the Link Manager procedures
/// # Arguments
/// * `lm` - link manager pointer
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointer
void link_manager_tick(const LinkManager* lm);

/// Process an HCI packet with the link manager
/// Returns true if successful
/// # Arguments
/// * `lm` - link manager pointer
/// * `data` - HCI packet data
/// * `len` - HCI packet len
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointer
/// - `data` must be valid for reads of len `len`
bool link_manager_ingest_hci(const LinkManager* lm, const uint8_t* data, uintptr_t len);

/// Process an LMP packet from a peer with the link manager
/// Returns true if successful
/// # Arguments
/// * `lm` - link manager pointer
/// * `from` - Address of peer as array of 6 bytes
/// * `data` - HCI packet data
/// * `len` - HCI packet len
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointers
/// - `from` must be valid pointer for reads for 6 bytes
/// - `data` must be valid for reads of len `len`
bool link_manager_ingest_lmp(const LinkManager* lm, const uint8_t (*from)[6], const uint8_t* data,
                             uintptr_t len);

/// Deallocate the link manager instance
/// # Arguments
/// * `lm` - link manager pointer
/// # Safety
/// - This should be called from the thread of creation
/// - `lm` must be a valid pointers and must not be reused afterwards
void link_manager_destroy(const LinkManager* lm);

/// Create a new link manager instance
/// # Arguments
/// * `ops` - Function callbacks required by the link manager
const LinkLayer* link_layer_create(ControllerOps ops);

/// Register a new link with a peer inside the link layer
/// # Arguments
/// * `ll` - link layer pointer
/// * `handle` - connection handle for the link
/// * `peer_address` - peer address as array of 6 bytes
/// * `role` - connection role (peripheral or centrl) for the link
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointer
/// - `peer` must be valid for reads for 6 bytes
/// - `role` must be 0 (central) or 1 (peripheral)
bool link_layer_add_link(const LinkLayer* ll, uint16_t handle, const uint8_t (*peer_address)[6],
                         uint8_t role);

/// Unregister a link with a peer inside the link layer
/// Returns true if successful
/// # Arguments
/// * `ll` - link layer pointer
/// * `peer` - peer address as array of 6 bytes
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointer
/// - `peer` must be valid for reads for 6 bytes
bool link_layer_remove_link(const LinkLayer* ll, uint16_t handle);

/// Run the Link Manager procedures
/// # Arguments
/// * `ll` - link layer pointer
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointer
void link_layer_tick(const LinkLayer* ll);

/// Process an HCI packet with the link layer
/// Returns true if successful
/// # Arguments
/// * `ll` - link layer pointer
/// * `data` - HCI packet data
/// * `len` - HCI packet len
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointer
/// - `data` must be valid for reads of len `len`
bool link_layer_ingest_hci(const LinkLayer* ll, const uint8_t* data, uintptr_t len);

/// Process an LLCP packet from a peer with the link layer
/// Returns true if successful
/// # Arguments
/// * `ll` - link layer pointer
/// * `handle` - ACL handle of the connection
/// * `data` - HCI packet data
/// * `len` - HCI packet len
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointers
/// - `data` must be valid for reads of len `len`
bool link_layer_ingest_llcp(const LinkLayer* ll, uint16_t handle, const uint8_t* data,
                            uintptr_t len);

/// Query the connection handle for a CIS established with
/// the input CIS and CIG identifiers.
/// Returns true if successful
/// # Arguments
/// * `ll` - link layer pointer
/// * `cig_id` - Identifier of the established Cig
/// * `cis_id` - Identifier of the established Cis
/// * `cis_connection_handle` - Returns the handle of the CIS if connected
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointers
bool link_layer_get_cis_connection_handle(const LinkLayer* ll, uint8_t cig_id, uint8_t cis_id,
                                          uint16_t* cis_connection_handle);

/// Query the CIS and CIG identifiers for a CIS established with
/// the input CIS connection handle.
/// Returns true if successful
/// # Arguments
/// * `ll` - link layer pointer
/// * `cis_connection_handle` - CIS connection handle
/// * `cig_id` - Returns the CIG identifier
/// * `cis_id` - Returns the CIS identifier
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointers
bool link_layer_get_cis_information(const LinkLayer* ll, uint16_t cis_connection_handle,
                                    uint16_t* acl_connection_handle, uint8_t* cig_id,
                                    uint8_t* cis_id, uint16_t* max_sdu_tx);

/// Deallocate the link layer instance
/// # Arguments
/// * `ll` - link layer pointer
/// # Safety
/// - This should be called from the thread of creation
/// - `ll` must be a valid pointers and must not be reused afterwards
void link_layer_destroy(const LinkLayer* ll);

}  // extern "C"
