//#include "WProgram.h"
#include <mac.h>
#include <mrf24j40.h>
#include <rom_cfg.h>

static unsigned char seqnum= 0;

static int CAN_SEND= 1;
static int TX_EVENT= 0;
static int RX_EVENT= 0;

const unsigned short PANID= 0x0001;

typedef struct {
  mac_frame     frame;
  unsigned char rssi;
  unsigned char lqi;
} frame_queue_entry_t;

#define FRAMES_QUEUE_DEPTH 2
static frame_queue_entry_t frames[FRAMES_QUEUE_DEPTH];
unsigned char frames_in_ptr= 0;
unsigned char frames_out_ptr= 0;
unsigned char frames_depth= 0;

void mac_init() {
  print("mac:init\n\r");
  mrf24j40_init(NULL, PANID,
		eeprom_config.saddr,
		eeprom_config.mac_addr,
		eeprom_config.channel, 0);

  if (eeprom_config.is_mb == 0xbb) {
    print("Device is MRF24J40MB\n");

    // Set the maximum tx power to -14.9dB (-10dB + -4.9dB)
    // required for compliance with ETSI (Europe)
    mrf24j40_set_tx_power(NULL, 1, 6);

    // Configure automatic use of the external PA/LNA by the RF
    // state machine
    unsigned char v;
    mrf24j40_long_read(NULL, MRF24J40_LREG_TESTMODE, &v);
    v|= 0x07;
    mrf24j40_long_write(NULL, MRF24J40_LREG_TESTMODE, v);
  }

}

static inline void _get_frame() {
  frame_queue_entry_t * entry;
  entry= &frames[frames_in_ptr];
  assert(mrf24j40_rx(NULL, &entry->frame, &entry->rssi, &entry->lqi) >= 0);
  frames_in_ptr= (frames_in_ptr + 1) % FRAMES_QUEUE_DEPTH;
  frames_depth++;
}

void mac_process_int(int intstat) {
  if (intstat & MRF24J40_INTSTAT_TXNIF) {
    int status;
    assert(mrf24j40_tx_status(NULL, &status) >= 0);
    CAN_SEND= 1;
  }

  if (intstat & MRF24J40_INTSTAT_RXIF) {
    if (frames_depth < FRAMES_QUEUE_DEPTH)
      _get_frame(); // Immediately retrieve frame from transceiver
    else
      RX_EVENT= 1; // Queue full -> flag frame received for later processing
  }

  /*if (intstat & MRF24J40_INTSTAT_WAKEIF)
    WAKE_EVENT= 1;*/
}

int mac_can_send() {
  return CAN_SEND;
}

void mac_send(saddr_t dst, unsigned char type, int ack_request,
	      const unsigned char * payload, unsigned char payload_len) {
  unsigned char mac_payload[128];
  mac_payload[0]= type;
  memcpy(&mac_payload[1], payload, payload_len);
  cli();
  CAN_SEND= 0;
  mrf24j40_tx(NULL, PANID, eeprom_config.saddr, dst, seqnum++, ack_request,
	      (const char *) mac_payload, payload_len+1);
  sei();
}

int mac_frame_available() {
  if (RX_EVENT && (frames_depth < FRAMES_QUEUE_DEPTH)) {
    cli();
    _get_frame();
    sei();
  }
  return (frames_depth > 0);
}

void mac_recv(mac_frame * frame, unsigned char * rssi, unsigned char * lqi) {
  frame_queue_entry_t * entry= &frames[frames_out_ptr];
  *frame= entry->frame;
  *rssi= entry->rssi;
  *lqi= entry->lqi;
  frames_out_ptr= (frames_out_ptr + 1) % FRAMES_QUEUE_DEPTH;
  frames_depth--;
}
