/*
 * Copyright (c) 2023 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <string.h>
#include <errno.h>
#include <zephyr/cache.h>
#include <zephyr/ipc/pbuf.h>
#include <zephyr/sys/byteorder.h>

/* Helper funciton for getting numer of bytes being written to the bufer. */
static uint32_t idx_occupied(uint32_t len, uint32_t wr_idx, uint32_t rd_idx)
{
	/* It is implicitly assumed wr_idx and rd_idx cannot differ by more then len. */
	return (rd_idx > wr_idx) ? (len - (rd_idx - wr_idx)) : (wr_idx - rd_idx);
}

/* Helper function for wrapping the index from the begging if above buffer len. */
static uint32_t idx_wrap(uint32_t len, uint32_t idx)
{
	return (idx >= len) ? (idx % len) : (idx);
}

static int validate_cfg(const struct pbuf_cfg *cfg)
{
	/* Validate pointers. */
	if (!cfg || !cfg->rd_idx_loc || !cfg->wr_idx_loc || !cfg->data_loc) {
		return -EINVAL;
	}

	/* Validate pointer alignment. */
	if (!IS_PTR_ALIGNED_BYTES(cfg->rd_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) ||
	    !IS_PTR_ALIGNED_BYTES(cfg->wr_idx_loc, MAX(cfg->dcache_alignment, _PBUF_IDX_SIZE)) ||
	    !IS_PTR_ALIGNED_BYTES(cfg->data_loc, _PBUF_IDX_SIZE)) {
		return -EINVAL;
	}

	/* Validate len. */
	if (cfg->len < _PBUF_MIN_DATA_LEN || !IS_PTR_ALIGNED_BYTES(cfg->len, _PBUF_IDX_SIZE)) {
		return -EINVAL;
	}

	/* Validate pointer values. */
	if (!(cfg->rd_idx_loc < cfg->wr_idx_loc) ||
	    !((uint8_t *)cfg->wr_idx_loc < cfg->data_loc) ||
	    !(((uint8_t *)cfg->rd_idx_loc + MAX(_PBUF_IDX_SIZE, cfg->dcache_alignment)) ==
	    (uint8_t *)cfg->wr_idx_loc)) {
		return -EINVAL;
	}

	return 0;
}

int pbuf_init(struct pbuf *pb)
{
	if (validate_cfg(pb->cfg) != 0) {
		return -EINVAL;
	}

	/* Initialize local copy of indexes. */
	pb->data.wr_idx = 0;
	pb->data.rd_idx = 0;

	/* Clear shared memory. */
	*(pb->cfg->wr_idx_loc) = pb->data.wr_idx;
	*(pb->cfg->rd_idx_loc) = pb->data.rd_idx;

	__sync_synchronize();

	/* Take care cache. */
	sys_cache_data_flush_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc)));
	sys_cache_data_flush_range((void *)(pb->cfg->rd_idx_loc), sizeof(*(pb->cfg->rd_idx_loc)));

	return 0;
}

int pbuf_write(struct pbuf *pb, const char *data, uint16_t len)
{
	if (pb == NULL || len == 0 || data == NULL) {
		/* Incorrect call. */
		return -EINVAL;
	}

	/* Invalidate rd_idx only, local wr_idx is used to increase buffer security. */
	sys_cache_data_invd_range((void *)(pb->cfg->rd_idx_loc), sizeof(*(pb->cfg->rd_idx_loc)));
	__sync_synchronize();

	uint8_t *const data_loc = pb->cfg->data_loc;
	const uint32_t blen = pb->cfg->len;
	uint32_t rd_idx = *(pb->cfg->rd_idx_loc);
	uint32_t wr_idx = pb->data.wr_idx;

	/* wr_idx must always be aligned. */
	__ASSERT_NO_MSG(IS_PTR_ALIGNED_BYTES(wr_idx, _PBUF_IDX_SIZE));
	/* rd_idx shall always be aligned, but its value is received from the reader.
	 * Can not assert.
	 */
	if (!IS_PTR_ALIGNED_BYTES(rd_idx, _PBUF_IDX_SIZE)) {
		return -EINVAL;
	}

	uint32_t free_space = blen - idx_occupied(blen, wr_idx, rd_idx) - _PBUF_IDX_SIZE;

	/* Packet length, data + packet length size. */
	uint32_t plen = len + PBUF_PACKET_LEN_SZ;

	/* Check if packet will fit into the buffer. */
	if (free_space < plen) {
		return -ENOMEM;
	}

	/* Clear packet len with zeros and update. Clearing is done for possible versioning in the
	 * future. Writing is allowed now, because shared wr_idx value is updated at the very end.
	 */
	*((uint32_t *)(&data_loc[wr_idx])) = 0;
	sys_put_be16(len, &data_loc[wr_idx]);
	__sync_synchronize();
	sys_cache_data_flush_range(&data_loc[wr_idx], PBUF_PACKET_LEN_SZ);

	wr_idx = idx_wrap(blen, wr_idx + PBUF_PACKET_LEN_SZ);

	/* Write until end of the buffer, if data will be wrapped. */
	uint32_t tail = MIN(len, blen - wr_idx);

	memcpy(&data_loc[wr_idx], data, tail);
	sys_cache_data_flush_range(&data_loc[wr_idx], tail);

	if (len > tail) {
		/* Copy remaining data to buffer front. */
		memcpy(&data_loc[0], data + tail, len - tail);
		sys_cache_data_flush_range(&data_loc[0], len - tail);
	}

	wr_idx = idx_wrap(blen, ROUND_UP(wr_idx + len, _PBUF_IDX_SIZE));
	/* Update wr_idx. */
	pb->data.wr_idx = wr_idx;
	*(pb->cfg->wr_idx_loc) = wr_idx;
	__sync_synchronize();
	sys_cache_data_flush_range((void *)pb->cfg->wr_idx_loc, sizeof(*(pb->cfg->wr_idx_loc)));

	return len;
}

int pbuf_read(struct pbuf *pb, char *buf, uint16_t len)
{
	if (pb == NULL) {
		/* Incorrect call. */
		return -EINVAL;
	}

	/* Invalidate wr_idx only, local rd_idx is used to increase buffer security. */
	sys_cache_data_invd_range((void *)(pb->cfg->wr_idx_loc), sizeof(*(pb->cfg->wr_idx_loc)));
	__sync_synchronize();

	uint8_t *const data_loc = pb->cfg->data_loc;
	const uint32_t blen = pb->cfg->len;
	uint32_t wr_idx = *(pb->cfg->wr_idx_loc);
	uint32_t rd_idx = pb->data.rd_idx;

	/* rd_idx must always be aligned. */
	__ASSERT_NO_MSG(IS_PTR_ALIGNED_BYTES(rd_idx, _PBUF_IDX_SIZE));
	/* wr_idx shall always be aligned, but its value is received from the
	 * writer. Can not assert.
	 */
	if (!IS_PTR_ALIGNED_BYTES(wr_idx, _PBUF_IDX_SIZE)) {
		return -EINVAL;
	}

	if (rd_idx == wr_idx) {
		/* Buffer is empty. */
		return 0;
	}

	/* Get packet len.*/
	sys_cache_data_invd_range(&data_loc[rd_idx], PBUF_PACKET_LEN_SZ);
	uint16_t plen = sys_get_be16(&data_loc[rd_idx]);

	if (!buf) {
		return (int)plen;
	}

	if (plen > len) {
		return -ENOMEM;
	}

	uint32_t occupied_space = idx_occupied(blen, wr_idx, rd_idx);

	if (occupied_space < plen + PBUF_PACKET_LEN_SZ) {
		/* This should never happen. */
		return -EAGAIN;
	}

	rd_idx = idx_wrap(blen, rd_idx + PBUF_PACKET_LEN_SZ);

	/* Packet will fit into provided buffer, truncate len if provided len
	 * is bigger than necessary.
	 */
	len = MIN(plen, len);

	/* Read until end of the buffer, if data are wrapped. */
	uint32_t tail = MIN(blen - rd_idx, len);

	sys_cache_data_invd_range(&data_loc[rd_idx], tail);
	memcpy(buf, &data_loc[rd_idx], tail);

	if (len > tail) {
		sys_cache_data_invd_range(&data_loc[0], len - tail);
		memcpy(&buf[tail], &pb->cfg->data_loc[0], len - tail);
	}

	/* Update rd_idx. */
	rd_idx = idx_wrap(blen, ROUND_UP(rd_idx + len, _PBUF_IDX_SIZE));

	pb->data.rd_idx = rd_idx;
	*(pb->cfg->rd_idx_loc) = rd_idx;
	__sync_synchronize();
	sys_cache_data_flush_range((void *)pb->cfg->rd_idx_loc, sizeof(*(pb->cfg->rd_idx_loc)));

	return len;
}
