/**
 * @file config.h
 * @brief Final AT configuration model for TCP2UART.
 */

#ifndef __CONFIG_H__
#define __CONFIG_H__

#include <stdbool.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define CONFIG_MAGIC             0x54435055u
#define CONFIG_VERSION           0x0003u

#define CONFIG_UART_COUNT        2u
#define CONFIG_LINK_COUNT        4u

#define CONFIG_LINK_S1           0u
#define CONFIG_LINK_S2           1u
#define CONFIG_LINK_C1           2u
#define CONFIG_LINK_C2           3u

#define ENDPOINT_C1              0x01u
#define ENDPOINT_C2              0x02u
#define ENDPOINT_UART2           0x04u
#define ENDPOINT_UART3           0x08u
#define ENDPOINT_S1              0x10u
#define ENDPOINT_S2              0x20u

#define LINK_UART_U0             0u
#define LINK_UART_U1             1u

typedef enum {
    MUX_MODE_RAW = 0,
    MUX_MODE_FRAME = 1
} mux_mode_t;

typedef struct {
    uint8_t ip[4];
    uint8_t mask[4];
    uint8_t gw[4];
    uint8_t mac[6];
    uint8_t reserved[2];
} net_config_t;

typedef struct {
    uint8_t enabled;
    uint8_t uart;
    uint16_t local_port;
    uint8_t remote_ip[4];
    uint16_t remote_port;
    uint16_t reserved;
} link_config_t;

typedef struct {
    uint32_t magic;
    uint16_t version;
    uint8_t mux_mode;
    uint8_t reserved0;
    net_config_t net;
    link_config_t links[CONFIG_LINK_COUNT];
    uint32_t uart_baudrate[CONFIG_UART_COUNT];
    uint32_t crc;
} device_config_t;

#define DEFAULT_NET_IP           {192, 168, 1, 100}
#define DEFAULT_NET_MASK         {255, 255, 255, 0}
#define DEFAULT_NET_GW           {192, 168, 1, 1}
#define DEFAULT_NET_MAC          {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
#define DEFAULT_UART_BAUDRATE    115200u

typedef enum {
    AT_OK = 0,
    AT_ERROR,
    AT_INVALID_PARAM,
    AT_UNKNOWN_CMD,
    AT_SAVE_FAILED,
    AT_NEED_REBOOT
} at_result_t;

int config_init(void);
int config_load(void);
int config_save(void);
void config_set_defaults(void);
const device_config_t *config_get(void);
device_config_t *config_get_mutable(void);
at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_len);
void config_poll(void);
void config_uart_rx_byte(uint8_t byte);
bool config_try_process_frame(const uint8_t *data, uint16_t len);
bool config_build_response_frame(const uint8_t *data,
                                 uint16_t len,
                                 char *response,
                                 uint16_t max_len,
                                 at_result_t *result);
bool config_is_reset_requested(void);
void config_clear_reset_requested(void);
void config_ip_to_str(const uint8_t *ip, char *str);
int config_str_to_ip(const char *str, uint8_t *ip);
void config_mac_to_str(const uint8_t *mac, char *str);
int config_str_to_mac(const char *str, uint8_t *mac);
uint8_t config_link_index_to_endpoint(uint8_t index);
uint8_t config_uart_index_to_endpoint(uint8_t uart_index);
bool config_endpoint_is_single(uint8_t endpoint);

#ifdef __cplusplus
}
#endif

#endif /* __CONFIG_H__ */
