/****************************************************************************
 * drivers/rpmsg/rpmsg_port.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you 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.
 *
 ****************************************************************************/

#ifndef __DRIVERS_RPMSG_RPMSG_PORT_H
#define __DRIVERS_RPMSG_RPMSG_PORT_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <stdbool.h>

#include <nuttx/list.h>
#include <nuttx/spinlock.h>
#include <nuttx/semaphore.h>
#include <nuttx/rpmsg/rpmsg_port.h>

#include "rpmsg.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#define rpmsgvbs                rpmsgerr

#define RPMSG_PORT_DROP_TXQ     0x01
#define RPMSG_PORT_DROP_RXQ     0x02
#define RPMSG_PORT_DROP_ALL     0x03

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* This header is for physical layer's use */

begin_packed_struct struct rpmsg_port_header_s
{
  uint16_t crc;                   /* CRC of current port data frame */
  uint16_t cmd;                   /* Reserved for uart/spi port driver */
  uint16_t avail;                 /* Available rx buffer of peer side */
  uint16_t len;                   /* Data frame length */
  uint8_t  buf[0];                /* Payload buffer */
} end_packed_struct;

struct rpmsg_port_list_s
{
  uint16_t         num;           /* Number of buffers */
  sem_t            sem;           /* Used to wait for buffer */
  spinlock_t       lock;          /* List lock */
  struct list_node head;          /* List head */
};

struct rpmsg_port_s;

struct rpmsg_port_queue_s
{
  /* Pointer to the rpmsg port handler */

  FAR struct rpmsg_port_s  *port;

  /* Indicate buffers current queue managed is dynamic alloced */

  bool                     alloced;

  /* Buffer array's base address of current queue managed */

  FAR void                 *buf;

  /* Node related to buffer for buffer management */

  FAR struct list_node     *node;

  /* Length of buffers current queue managed */

  uint16_t                 len;

  /* Free list of buffers which have not been occupied data yet */

  struct rpmsg_port_list_s free;

  /* Ready list of buffers which have been occupied data already */

  struct rpmsg_port_list_s ready;
};

typedef void (*rpmsg_port_rx_cb_t)(FAR struct rpmsg_port_s *port,
                                   FAR struct rpmsg_port_header_s *hdr);

struct rpmsg_port_ops_s
{
  /* Notify driver there is buffer to be sent of the tx queue */

  CODE void (*notify_tx_ready)(FAR struct rpmsg_port_s *port);

  /* Notify driver there is a buffer in rx queue is freed */

  CODE void (*notify_rx_free)(FAR struct rpmsg_port_s *port);

  /* Notify driver there is no available buffer */

  CODE int (*notify_queue_noavail)(FAR struct rpmsg_port_s *port,
                                   FAR struct rpmsg_port_queue_s *queue);

  /* Register callback function which should be invoked when there is
   * date received to the rx queue by driver
   */

  CODE void (*register_callback)(FAR struct rpmsg_port_s *port,
                                 rpmsg_port_rx_cb_t callback);

  /* Dump the transport debug informations */

  CODE void (*dump)(FAR struct rpmsg_port_s *port, bool verbose);
};

struct rpmsg_port_s
{
  struct rpmsg_s                    rpmsg;
  struct rpmsg_device               rdev;   /* Rpmsg device object */
  struct rpmsg_port_queue_s         txq;    /* Port tx queue */
  struct rpmsg_port_queue_s         rxq;    /* Port rx queue */

  /* Ops need implemented by drivers under port layer */

  const FAR struct rpmsg_port_ops_s *ops;
};

#ifndef __ASSEMBLY__
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/****************************************************************************
 * Name: rpmsg_port_queue_get_available_buffer
 *
 * Description:
 *   Get buffer from free list of the queue.
 *
 * Input Parameters:
 *   queue - The queue to be getten from.
 *   wait  - If wait or not when there is no available buffer of the queue.
 *
 * Returned Value:
 *   A struct rpmsg_port_header_s's pointer on success or NULL on failure.
 *   The len of struct rpmsg_port_header_s indicates the sum of struct
 *   rpmsg_port_header_s's size and the data size can be used.
 *
 ****************************************************************************/

FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_available_buffer(FAR struct rpmsg_port_queue_s *queue,
                                      bool wait);

/****************************************************************************
 * Name: rpmsg_port_queue_return_buffer
 *
 * Description:
 *   Return buffer to free list of the queue.
 *
 * Input Parameters:
 *   queue - The queue to be returned to.
 *   hdr   - Pointer to the struct rpmsg_port_header_s to be returned.
 *
 * Returned Value:
 *   No return value.
 *
 ****************************************************************************/

void rpmsg_port_queue_return_buffer(FAR struct rpmsg_port_queue_s *queue,
                                    FAR struct rpmsg_port_header_s *hdr);

/****************************************************************************
 * Name: rpmsg_port_queue_get_buffer
 *
 * Description:
 *   Get buffer from ready list of the queue.
 *
 * Input Parameters:
 *   queue - The queue to be getten from.
 *   wait  - If wait or not when there is no used buffer of the queue.
 *
 * Returned Value:
 *   A struct rpmsg_port_header_s's pointer on success or NULL on failure.
 *   The len of struct rpmsg_port_header_s indicates the sum of struct
 *   rpmsg_port_header_s's size and the data size has be used.
 *
 ****************************************************************************/

FAR struct rpmsg_port_header_s *
rpmsg_port_queue_get_buffer(FAR struct rpmsg_port_queue_s *queue,
                            bool wait);

/****************************************************************************
 * Name: rpmsg_port_queue_add_buffer
 *
 * Description:
 *   Add buffer to ready list of the queue.
 *
 * Input Parameters:
 *   queue - The queue to be added to.
 *   hdr   - Pointer to the struct rpmsg_port_header_s to be added. The
 *           length of it must be set before this function invoked.
 *
 * Returned Value:
 *   No return value.
 *
 ****************************************************************************/

void rpmsg_port_queue_add_buffer(FAR struct rpmsg_port_queue_s *queue,
                                 FAR struct rpmsg_port_header_s *hdr);

/****************************************************************************
 * Name: rpmsg_port_queue_navail
 *
 * Description:
 *   Get available buffer number of free list of the queue.
 *
 * Input Parameters:
 *   queue - The queue is to be calculated.
 *
 * Returned Value:
 *   Number of available buffers.
 *
 ****************************************************************************/

static inline_function
uint16_t rpmsg_port_queue_navail(FAR struct rpmsg_port_queue_s *queue)
{
  irqstate_t flags;
  uint16_t num;

  flags = spin_lock_irqsave(&queue->free.lock);
  num = queue->free.num;
  spin_unlock_irqrestore(&queue->free.lock, flags);
  return num;
}

/****************************************************************************
 * Name: rpmsg_port_queue_nused
 *
 * Description:
 *   Get used buffer number of ready list of the queue.
 *
 * Input Parameters:
 *   queue - The queue is to be calculated.
 *
 * Returned Value:
 *   Number of used buffers.
 *
 ****************************************************************************/

static inline_function
uint16_t rpmsg_port_queue_nused(FAR struct rpmsg_port_queue_s *queue)
{
  irqstate_t flags;
  uint16_t num;

  flags = spin_lock_irqsave(&queue->free.lock);
  num = queue->ready.num;
  spin_unlock_irqrestore(&queue->free.lock, flags);
  return num;
}

/****************************************************************************
 * Name: rpmsg_port_update_timestamp
 ****************************************************************************/

void rpmsg_port_update_timestamp(FAR struct rpmsg_port_queue_s *queue,
                                 FAR struct rpmsg_port_header_s *hdr,
                                 bool tx);

/****************************************************************************
 * Name: rpmsg_port_drop_packets
 ****************************************************************************/

void rpmsg_port_drop_packets(FAR struct rpmsg_port_s *rport, uint8_t type);

/****************************************************************************
 * Name: rpmsg_port_initialize
 *
 * Description:
 *   Init port layer by port's configuration. rpmsg port layer creates and
 *   manages queues used for communication of two cpus.
 *
 * Input Parameters:
 *   port - The port to be inited.
 *   cfg  - Port configuration.
 *   ops  - Operation implemented by drivers under port layer.
 *
 * Returned Value:
 *   Zero on success or an negative value on failure.
 *
 ****************************************************************************/

int rpmsg_port_initialize(FAR struct rpmsg_port_s *port,
                          FAR const struct rpmsg_port_config_s *cfg,
                          FAR const struct rpmsg_port_ops_s *ops);

/****************************************************************************
 * Name: rpmsg_port_uninitialize
 *
 * Description:
 *   uninit rpmsg port.
 *
 * Input Parameters:
 *   port - The port to be uninited.
 *
 * Returned Value:
 *   No return value.
 *
 ****************************************************************************/

void rpmsg_port_uninitialize(FAR struct rpmsg_port_s *port);

/****************************************************************************
 * Name: rpmsg_port_register
 *
 * Description:
 *   Invoked to create a rpmsg character device when a connection between
 *   two cpus has established.
 *
 * Input Parameters:
 *   port          - The port has established a connection.
 *   local_cpuname - The local cpuname
 *
 * Returned Value:
 *   Zero on success or an negative value on failure.
 *
 ****************************************************************************/

int rpmsg_port_register(FAR struct rpmsg_port_s *port,
                        FAR const char *local_cpuname);

/****************************************************************************
 * Name: rpmsg_port_unregister
 *
 * Description:
 *   Invoked to unregister the rpmsg character device.
 *
 * Input Parameters:
 *   port - The port has established a connection.
 *
 * Returned Value:
 *   No return value.
 *
 ****************************************************************************/

void rpmsg_port_unregister(FAR struct rpmsg_port_s *port);

#undef EXTERN
#ifdef __cplusplus
}
#endif

#endif
#endif /* __DRIVERS_RPMSG_RPMSG_PORT_H */