#ifndef LIBTTN_TTN_DEVICE_H
#define LIBTTN_TTN_DEVICE_H
/****************************************************************************************************************/

#include "ttn/lnk/ttn.h"

struct ttn_lnk_device_t;
struct ttn_lnk_handle_t;

struct ttn_lnk_device_operations_t {
  void (*transmit)(struct ttn_lnk_device_t *handle, const void *data, size_t len);
  void (*receive)(struct ttn_lnk_device_t *handle);
  void (*set_speed)(struct ttn_lnk_device_t *handle, unsigned int bitspersecond);
  void (*close)(struct ttn_lnk_device_t *handle);
  void (*online)(struct ttn_lnk_device_t *handle, bool is_online);
};

struct ttn_lnk_device_t {
  struct ttn_lnk_handle_t *ad_ttn;
  const struct ttn_lnk_device_operations_t *ad_ops;
  unsigned int cobs_code;
  unsigned int cobs_block;
  size_t cobs_dstidx;
};

// COBS needs one extra byte per each 254 source bytes. Or so.
// Too lazy to calculate this exactly, so give one extra byte every 250 and call it a day.
// Add a few extra for headering, rounding or whatever.
#define TTN_COBS_BUFSIZE (TTN_MAX_PACKET_SIZE + 8 + TTN_MAX_PACKET_SIZE / 250)

// Encode transmit frame for putting on the line
size_t ttn_lnk_encode_cobs(void *buffer, const void *data, size_t len); // Buffer must be of size 'TTN_COBS_BUFSIZE'

// COBS framed data has been received
void ttn_lnk_process_cobs(struct ttn_lnk_device_t *dev, const void *data, size_t length);

// Discard any half-finished receive packet
void ttn_lnk_flush_cobs(struct ttn_lnk_device_t *dev);

// Receive buffer where to place the received de-framed packet data
// This buffer is subject to change after each call to ttn_lnk_process_packet()
static inline uint8_t *ttn_lnk_receive_buffer(struct ttn_lnk_device_t *dev);

// There is traffic, whether correct or malformed, on the receiver.
static inline void ttn_lnk_traffic_seen(struct ttn_lnk_device_t *dev);

// A de-framed packet has been placed into the receive buffer
void ttn_lnk_process_packet(struct ttn_lnk_device_t *dev, size_t len);

// Calculate time in ms that is required to transmit «byte_count» bytes
unsigned int ttn_lnk_transmission_time(struct ttn_lnk_handle_t *ttn, size_t byte_count);

/****************************************************************************************************************/

#include "ttn/lnk/handle.h"

static inline uint8_t *ttn_lnk_receive_buffer(struct ttn_lnk_device_t *dev) {
  return (uint8_t *)ttn_pkb_packet(dev->ad_ttn->ttn_rxbuf);
}

static inline void ttn_lnk_traffic_seen(struct ttn_lnk_device_t *dev) {
  struct ttn_lnk_handle_t *ttn = dev->ad_ttn;
  ttn->ttn_traffic_seen = 1;
}

/****************************************************************************************************************/

#endif
