/* -*- c -*- */
/* 
 * Copyright (c) 2021 Satlab A/S <satlab@satlab.com>
 * 
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _SL_SPACEFRAME_H_
#define _SL_SPACEFRAME_H_

#define SPACEFRAME_CRC_LENGTH		sizeof(uint32_t)

#define SPACEFRAME_RS_DATA_SIZE		223
#define SPACEFRAME_RS_PAR_SIZE		32

#define SPACEFRAME_CC_RATE		2
#define SPACEFRAME_CC_TAIL		1
#define SPACEFRAME_CC_CONSTR		7

/* CCSDS 131.0-B-3 ASM */
#define SPACEFRAME_ASM			0x1ACFFC1D
#define SPACEFRAME_ASM_LENGTH		sizeof(uint32_t)

/* Convolutional encoded ASM assuming zero-state LFSR */
#define SPACEFRAME_ASM_CC1		0x56081C97
#define SPACEFRAME_ASM_CC2		0x1AA73D3E

/* Header */
#define SPACEFRAME_ID_LENGTH		sizeof(uint16_t)

/* Header */
#define SPACEFRAME_HEADER_LENGTH	sizeof(uint16_t)

/* Maximum payload size is 1024 bytes */
#define SPACEFRAME_PAYLOAD_LENGTH_MAX	1024

/* Crypto IV length */
#define SPACEFRAME_CRYPTO_IV_LENGTH	12

/* Crypto tag length */
#define SPACEFRAME_CRYPTO_TAG_LENGTH	16

/* Calculate maximum encoded size (without preamble) */
#define SPACEFRAME_RS_LENGTH_MAX	(SPACEFRAME_HEADER_LENGTH + \
					 SPACEFRAME_ID_LENGTH + \
					 SPACEFRAME_PAYLOAD_LENGTH_MAX + \
					 SPACEFRAME_CRC_LENGTH + \
					 SPACEFRAME_CRYPTO_IV_LENGTH + \
					 SPACEFRAME_CRYPTO_TAG_LENGTH)

#define SPACEFRAME_CC_LENGTH_MAX	(SPACEFRAME_ASM_LENGTH + \
					 SPACEFRAME_RS_LENGTH_MAX + \
					(((SPACEFRAME_RS_LENGTH_MAX + SPACEFRAME_RS_DATA_SIZE + 1) / SPACEFRAME_RS_DATA_SIZE) * SPACEFRAME_RS_PAR_SIZE)) /* Plus RS parity */

#define SPACEFRAME_LENGTH_MAX		((SPACEFRAME_CC_LENGTH_MAX + SPACEFRAME_CC_TAIL) * SPACEFRAME_CC_RATE) /* Plus CC */

/* Maximum preamble and postamble bytes */
#define SPACEFRAME_PREAMBLE_LENGHT_MAX	128

/* Frame types (4 bits) */
enum spaceframe_type {
	SPACEFRAME_TYPE_CSP = 0,
	SPACEFRAME_TYPE_IP = 1,
	/* Must be last */
	SPACEFRAME_TYPE_MAX = 15,
};

/* Spaceframe header:
 *
 *  0                   1
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |R| Type  |       Length        |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * R = reserved for future use.
 */

#define SPACEFRAME_RES_BITS	1
#define SPACEFRAME_TYPE_BITS	4
#define SPACEFRAME_LENGTH_BITS	11

static inline uint16_t spaceframe_header_make(enum spaceframe_type type, uint16_t len)
{
	return (((uint16_t)type & ((1 << SPACEFRAME_TYPE_BITS) - 1)) << SPACEFRAME_LENGTH_BITS) | \
		(len & ((1 << SPACEFRAME_LENGTH_BITS) - 1));
}

static inline enum spaceframe_type spaceframe_header_type(uint16_t header)
{
	return (enum spaceframe_type)((header >> SPACEFRAME_LENGTH_BITS) & ((1 << SPACEFRAME_TYPE_BITS) - 1));
}

static inline size_t spaceframe_header_length(uint16_t header)
{
	return header & ((1 << SPACEFRAME_LENGTH_BITS) - 1);
}

#endif /* _SL_SPACEFRAME_H_ */
