/** 
 * @file    shot_storage.h
 * @brief   Shot Storage Module
 * @author  Kenny Tran
 * @date    Sep 02 2025
 * @version 0.0.1
 *
 * @section LICENSES
 * Copyright (C) Morgan Advanced Programmable Systems, Inc.
 */


#ifndef SHOT_STORAGE_H_
#define SHOT_STORAGE_H_


/*--------------------------------------------------------------------------------------------------
 * INCLUDE FILES
 *------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "../lib/errno.h"

#include "../app/motion.h"


/*--------------------------------------------------------------------------------------------------
 * MACROS & CONSTANTS
 *------------------------------------------------------------------------------------------------*/
#define SHOT_STORAGE_WRITE_THREAD_STACK_SIZE (1024)
#define SHOT_STORAGE_READ_THREAD_STACK_SIZE  (1024)
#define SHOT_STORAGE_WRITE_THREAD_PRIORITY   (10)
#define SHOT_STORAGE_READ_THREAD_PRIORITY    (5)

#define SHOT_STORAGE_MAX_FILES          (16)

#define SHOT_STORAGE_FILENAME_LEN       (16)

#define SHOT_STORAGE_TRACKING_FILENAME    ("shot_strg_trk")
#define SHOT_STORAGE_TRACKING_FILE_SECTOR (3)

#define _SHOT_STORAGE_SPLIT_BYTE(x, offset)     (0xFF & (x >> (8 * offset)))

#define _SHOT_STORAGE_START_ADDR                (NVM_EXT_SIZE / 2)
#define _SHOT_STORAGE_END_ADDR                  (NVM_EXT_SIZE - 1)

#define _SHOT_STORAGE_SECTOR_SIZE               (4096)

#define _SHOT_STORAGE_TOTAL_FILE_SIZE           (65536)
#define _SHOT_STORAGE_FILE_SIZE                 (_SHOT_STORAGE_TOTAL_FILE_SIZE - sizeof(SHOT_STORAGE_file_s))


/*--------------------------------------------------------------------------------------------------
 * TYPE DEFINITIONS & ENUMERATIONS
 *------------------------------------------------------------------------------------------------*/
typedef struct
{
    uint8_t                     header_ver;
    uint32_t                    power_cnt;
    uint32_t                    time_of_shot;
    uint32_t                    reserved;
    uint8_t                     shot_data_format_ver;
    uint32_t                    ambient_light_intensity;
    uint32_t                    shot_data_offset;
    uint32_t                    shot_data_size;
    uint8_t                     gyro_bits_per_axis;
    uint8_t                     accel_bits_per_axis;
    uint16_t                    gyro_sample_rate_hz;
    uint16_t                    accel_sample_rate_hz;
    uint16_t                    gyro_full_scale_dps;
    uint8_t                     accel_full_scale_g;
    uint16_t                    IMU_orientation;
    MOTION_calibration_data_s   accel_cal;
    MOTION_calibration_data_s   gyro_cal;
} __attribute__((packed, aligned(1))) SHOT_STORAGE_file_s;

/**
 * @brief Tracking info for circular file storage.
 *        Persisted to internal flash across reboots.
 */
typedef struct
{
    uint32_t write_idx;       /* Next slot to write to (0 to MAX_FILES-1, wraps) */
    uint32_t file_cnt;        /* Number of valid files currently stored (0 to MAX_FILES) */
    uint32_t total_written;   /* Total files ever written (monotonic, for unique naming) */
} __attribute__((packed, aligned(1))) SHOT_STORAGE_tracking_s;

/**
 * Stream cursor that presents a linear view over:
 * [header] + [circular buffer data starting at write_ptr]
 *
 * Handles all boundary crossings (header→data, buffer wrap) transparently.
 * The caller just asks for N bytes at a time.
 */
struct stream_cursor {
    const uint8_t *header;
    uint32_t header_size;

    const uint8_t *buffer;
    uint32_t data_size;       /* effective size the circular buffer wraps at */
    uint32_t write_ptr;       /* where writing stopped = logical start of data */
    uint32_t total;           /* header_size + data_size, computed once at init */

    uint32_t offset;          /* current position in the logical stream */
};

typedef enum {
    READ_REQ_NONE = 0,
    READ_REQ_CLI,
    READ_REQ_BLE,
} read_request_source_e;


/*--------------------------------------------------------------------------------------------------
 * PUBLIC VARIABLE
 *------------------------------------------------------------------------------------------------*/
extern struct k_sem read_shotdata_consumed;

/*--------------------------------------------------------------------------------------------------
 * PUBLIC FUNCTION PROTOTYPES
 *------------------------------------------------------------------------------------------------*/
void SHOT_STORAGE_init (void);

void SHOT_STORAGE_task_install (void);

ERRNO_e SHOT_STORAGE_get_buf(uint32_t size, uint8_t **pp_data);

ERRNO_e SHOT_STORAGE_file_create(void);

void SHOT_STORAGE_begin_write(void);

void SHOT_STORAGE_write(void);

bool SHOT_STORAGE_write_done (void);

uint8_t *SHOT_STORAGE_last_read (SHOT_STORAGE_file_s *p_file);

void SHOT_STORAGE_last_erase (void);

ERRNO_e SHOT_STORAGE_eraseall(void);

uint32_t SHOT_STORAGE_get_file_cnt(void);

void SHOT_STORAGE_cli_cmd (int32_t argc, char **argv);

void SHOT_STORAGE_stream_cursor_init(struct stream_cursor *cur,
                        const uint8_t *header, uint32_t header_size,
                        const uint8_t *buffer, uint32_t data_size,
                        uint32_t write_ptr);

uint32_t stream_cursor_read(struct stream_cursor *cur, uint8_t *dst, uint32_t len);

uint32_t stream_cursor_remaining(struct stream_cursor *cur);


void SHOT_STORAGE_wait_write_task_idle(void);

/**
 * @brief Request a shot data read from flash.
 * @param source Who is requesting (CLI or BLE).
 */
void SHOT_STORAGE_request_read(read_request_source_e source);

/**
 * @brief Wait until the read buffer is ready.
 * @return 0 on success, negative on error.
 */
int SHOT_STORAGE_wait_buf_ready(void);

/**
 * @brief Signal that the consumer has finished reading the buffer.
 */
void SHOT_STORAGE_read_done(void);


#endif /* SHOT_STORAGE_H_ */
