#ifndef BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_
#define BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_

#include "StarTrackerDefinitions.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"

extern "C" {
#include "common/misc.h"
}

/**
 * @brief   Helper class to handle the datalinklayer of replies from the star tracker of arcsec.
 */
class ArcsecDatalinkLayer : public HasReturnvaluesIF {
 public:
  static const uint8_t INTERFACE_ID = CLASS_ID::STR_HANDLER;

  //! [EXPORT] : [COMMENT] More data required to complete frame
  static const ReturnValue_t DEC_IN_PROGRESS = MAKE_RETURN_CODE(0xA0);
  //! [EXPORT] : [COMMENT] Data too short to represent a valid frame
  static const ReturnValue_t REPLY_TOO_SHORT = MAKE_RETURN_CODE(0xA1);
  //! [EXPORT] : [COMMENT] Detected CRC failure in received frame
  static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA2);

  static const uint8_t STATUS_OK = 0;

  ArcsecDatalinkLayer();
  virtual ~ArcsecDatalinkLayer();

  /**
   * @brief   Applies decoding to data referenced by rawData pointer
   *
   * @param rawData          Pointer to raw data received from star tracker
   * @param rawDataSize      Size of raw data stream
   * @param remainingBytes   Number of bytes left
   */
  ReturnValue_t decodeFrame(const uint8_t* rawData, size_t rawDataSize, size_t* bytesLeft);

  /**
   * @brief   SLIP encodes data pointed to by data pointer.
   *
   * @param data   Pointer to data to encode
   * @param length Length of buffer to encode
   */
  void encodeFrame(const uint8_t* data, uint32_t length);

  /**
   * @brief    Returns the frame type field of a decoded frame.
   */
  uint8_t getReplyFrameType();

  /**
   * @brief   Returns pointer to reply packet (first entry normally action ID, telemetry ID etc.)
   */
  const uint8_t* getReply();

  /**
   * @brief   Returns size of encoded frame
   */
  uint32_t getEncodedLength();

  /**
   * @brief   Returns pointer to encoded frame
   */
  uint8_t* getEncodedFrame();

  /**
   * @brief   Returns status of reply
   */
  uint8_t getStatusField();

  /**
   * @brief   Returns ID of reply
   */
  uint8_t getId();

 private:
  static const uint8_t ID_OFFSET = 1;
  static const uint8_t STATUS_OFFSET = 2;

  // Used by arcsec slip decoding function process received data
  uint8_t rxBuffer[StarTracker::MAX_FRAME_SIZE];
  // Decoded frame will be copied to this buffer
  uint8_t decodedFrame[StarTracker::MAX_FRAME_SIZE];
  // Buffer where encoded frames will be stored. First byte of encoded frame represents type of
  // reply
  uint8_t encBuffer[StarTracker::MAX_FRAME_SIZE * 2 + 2];
  // Size of decoded frame
  uint32_t decFrameSize = 0;
  // Size of encoded frame
  uint32_t encFrameSize = 0;

  slip_decode_state slipInfo;

  void slipInit();
};

#endif /* BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_ */