#ifndef INC_CLOCK_SYNC_H_
#define INC_CLOCK_SYNC_H_

#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_can.h"

#include <stdint.h>

#define CLOCK_TARGET_FREQ 16000000 // Hz
#define HSI_TRIM_FREQ 48000        // Hz
#define CLOCK_SYNC_INTERVAL 1000   // ms
#define CLOCK_SYNC_SANITY_INTERVAL_MIN 900
#define CLOCK_SYNC_SANITY_INTERVAL_MAX 1100
#define MASTER_HEARTBEAT_INTERVAL 100 // ms
#define MASTER_HEARTBEAT_SANITY_INTERVAL_MAX 110
#define MASTER_HEARTBEAT_DESYNC_THRESH                                         \
  (2 * MASTER_HEARTBEAT_SANITY_INTERVAL_MAX)
#define FREQ_HOPPING_TRIM_STEPS 2
#define FREQ_HOPPING_STAGE2_FRAMES 3
#define FREQ_HOPPING_STAGE2_MAX_ATTEMPTS 6
#define RCC_CR_HSITRIM_MAX 31
#define CLOCK_SYNC_MAX_TRANSMIT_ERRORS 64

typedef enum {
  CLOCK_SYNC_NORMAL_OPERATION,
  CLOCK_SYNC_FREQ_HOPPING_STAGE1,
  CLOCK_SYNC_FREQ_HOPPING_STAGE2
} ClockSyncState;

extern ClockSyncState clock_sync_state;

void clock_sync_init(CAN_HandleTypeDef* can_handle);
void clock_sync_update();
ClockSyncState clock_sync_update_normal_operation();
ClockSyncState clock_sync_update_freq_hopping_stage1();
ClockSyncState clock_sync_update_freq_hopping_stage2();
void clock_sync_start_normal_operation();
void clock_sync_start_freq_hopping_stage1();
void clock_sync_start_freq_hopping_stage2();
void clock_sync_handle_clock_sync_frame(uint8_t counter);
void clock_sync_handle_master_heartbeat();
void clock_sync_startup_check();
uint8_t get_hsi_trim();
void set_hsi_trim(uint8_t trim);
void trim_hsi_by(int32_t delta);

uint8_t calculate_freq_hopping_trim(uint32_t freq_hopping_iteration);

#endif // INC_CLOCK_SYNC_H_