/*
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of
 * the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Frank Holtz
 * Copyright (C) 2017 Frank Holtz
 * Full contributor list:
 * https://github.com/mysensors/MySensors/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 */

#ifndef __NRF5_ESB_H__
#define __NRF5_ESB_H__

#include "Radio.h"
#include <Arduino.h>

// Check maximum message length
#if MAX_MESSAGE_SIZE > (32)
#error "Unsupported message size. (MAX_MESSAGE_SIZE)"
#endif

// check rx buffer size
#if MY_NRF5_ESB_RX_BUFFER_SIZE < (4)
#error "MY_NRF5_ESB_RX_BUFFER_SIZE must be greater than 3."
#endif

/** Wait for start of an ACK packet in us
 * Calculation: ramp up time + packet header (57 Bit): round to 9 Byte
 * If you don't receive ACK packages, you have to increase this value.
 * My measured (Arduino Uno + nRF24L01P) minimal timeouts:
 *   250kbit 411us -> 182 us to ACK start
 *   1MBit   205us -> 147 us
 *   2MBit   173us -> 143 us
 */
#define NRF5_ESB_ACK_WAIT                                                      \
	((NRF5_ESB_RAMP_UP_TIME << 1) + (9 << NRF5_ESB_byte_time()))

/** Maximum time to transmit a complete packet after address event
 **/
#define NRF5_ESB_MAX_PACKET_TIME                                                \
	((MAX_MESSAGE_SIZE+sizeof(nrf5_radio_packet_s)) << NRF5_ESB_byte_time())

// auto retry delay in us, don't set this value < 1500us@250kbit
#define NRF5_ESB_ARD (1500)

// auto retry count with noACK is false
#define NRF5_ESB_ARC_ACK (3)

// auto retry count with noACK is true
#define NRF5_ESB_ARC_NOACK (3)

// How often broadcast messages are send
#define NRF5_ESB_BC_ARC (3)

// Node address index
#define NRF5_ESB_NODE_ADDR (0)
#define NRF5_ESB_NODE_ADDR_MSK (0xffffff00UL)

// TX address index
#define NRF5_ESB_TX_ADDR (4)
#define NRF5_ESB_TX_ADDR_MSK (0xffffff00UL)

// Broadcast address index
#define NRF5_ESB_BC_ADDR (7)
#define NRF5_ESB_BC_ADDR_MSK (0xffffffffUL)

// Interrupt mask RX
#define NRF5_EBS_RADIO_INT_RX (RADIO_INTENSET_ADDRESS_Msk | RADIO_INTENSET_END_Msk | RADIO_INTENSET_DISABLED_Msk)

// Interrupt mask TX
#define NRF5_EBS_RADIO_INT_TX (RADIO_INTENSET_ADDRESS_Msk | RADIO_INTENSET_DISABLED_Msk)

// Shorts for RX mode
#define NRF5_ESB_SHORTS_RX                                                     \
	(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_START_Msk |               \
	 RADIO_SHORTS_DISABLED_RXEN_Msk |                                          \
	 RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk)

// Shorts for TX mode
#define NRF5_ESB_SHORTS_TX                                                     \
	(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_START_Msk |               \
	 RADIO_SHORTS_DISABLED_TXEN_Msk)

// Shorts to switch from RX to TX
#define NRF5_ESB_SHORTS_RX_TX                                                  \
	(RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_DISABLED_TXEN_Msk |           \
	 RADIO_SHORTS_READY_START_Msk)

// Shorts to switch from TX to RX
#define NRF5_ESB_SHORTS_TX_RX                                                  \
	(RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_DISABLED_RXEN_Msk |           \
	 RADIO_SHORTS_READY_START_Msk |           \
	 RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk)

/** PPI Channels for TX
 * Not all NRF5 modules have the same number of PPI channels
 * For regular PPI, select the highest possible channels
 */
#define NRF5_ESB_PPI_LAST_CHANNEL (PPI_CH_NUM - 1)
#if (NRF5_RADIO_TIMER_IRQN != TIMER0_IRQn)
// Use two regular PPI channels
#define NRF5_ESB_PPI_TIMER_START (NRF5_ESB_PPI_LAST_CHANNEL - 1)
#define NRF5_ESB_PPI_TIMER_RADIO_DISABLE (NRF5_ESB_PPI_LAST_CHANNEL)
#else
// Use one regular PPI channel and one predefined PPI channel
#define NRF5_ESB_USE_PREDEFINED_PPI
#define NRF5_ESB_PPI_TIMER_START (NRF5_ESB_PPI_LAST_CHANNEL)
#define NRF5_ESB_PPI_TIMER_RADIO_DISABLE 22
#endif
#define NRF5_ESB_PPI_BITS                                                     \
	((1 << NRF5_ESB_PPI_TIMER_START) |                                        \
	 (1 << NRF5_ESB_PPI_TIMER_RADIO_DISABLE))

/** ramp up time
 * Time to activate radio TX or RX mode
 */
#define NRF5_ESB_RAMP_UP_TIME (140)


static bool NRF5_ESB_initialize();
static void NRF5_ESB_powerDown();
static void NRF5_ESB_powerUp();
static void NRF5_ESB_sleep();
static void NRF5_ESB_standBy();
static bool NRF5_ESB_sanityCheck();

static void NRF5_ESB_setNodeAddress(const uint8_t address);
static uint8_t NRF5_ESB_getNodeID();

static void NRF5_ESB_startListening();
static bool NRF5_ESB_isDataAvailable();
static uint8_t NRF5_ESB_readMessage(void *data);

static bool NRF5_ESB_sendMessage(uint8_t recipient, const void *buf, uint8_t len, const bool noACK);

static int16_t NRF5_ESB_getSendingRSSI();
static int16_t NRF5_ESB_getReceivingRSSI();

// Calculate time to transmit an byte in us as bit shift -> 2^X
static inline uint8_t NRF5_ESB_byte_time();

/** Structure of radio rackets
 */
typedef struct nrf5_radio_packet_s {
	// structure written by radio unit
	struct {
		uint8_t len;
		union {
			uint8_t s1;
			struct {
				uint8_t noack : 1;
				uint8_t pid : 2;
			};
		};
		uint8_t data[MAX_MESSAGE_SIZE];
		int8_t rssi;
		/** Debug data structure */
#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
		uint32_t rxmatch;
#endif
	}
#ifndef DOXYGEN
	__attribute__((packed));
#endif
} NRF5_ESB_Packet;

#ifdef MY_DEBUG_VERBOSE_NRF5_ESB
static uint32_t intcntr_addrmatch;
static uint32_t intcntr_ready;
static uint32_t intcntr_end;
static uint32_t intcntr_disabled;
static uint32_t intcntr_timer_cc3;
#endif

#endif // __NRF5_H__
