#pragma once

#include "s600_config.h"
#include "stdio.h"

#define CAN_PIN_MAP_PA11_PA12		1
#define CAN_PIN_MAP_PB8_PB9			2
#define CAN_PIN_MAP_PD0_PD1			3

#ifdef CONFIG_BOARD_S600
#define CONFIG_BOARD_NAME			"S600"
#define CONFIG_CAN_ID				0x41
#define CONFIG_CAN_PIN_MAP			CAN_PIN_MAP_PA11_PA12
#elif defined(CONFIG_BOARD_C200)
#define CONFIG_BOARD_NAME			"C200"
#define CONFIG_CAN_ID				0x43
#define CONFIG_CAN_PIN_MAP			CAN_PIN_MAP_PB8_PB9
#elif defined(CONFIG_BOARD_G580)
#define CONFIG_BOARD_NAME			"G580"
#define CONFIG_CAN_ID				0x50
#define CONFIG_CAN_PIN_MAP			CAN_PIN_MAP_PB8_PB9
#elif defined(CONFIG_BOARD_PS300)
#define CONFIG_BOARD_NAME			"PS300"
#define CONFIG_CAN_ID				0x43
#define CONFIG_CAN_PIN_MAP			CAN_PIN_MAP_PB8_PB9
#elif defined(CONFIG_BOARD_PS100)
#define CONFIG_BOARD_NAME			"PS100"
#define CONFIG_CAN_ID				0x42
#define CONFIG_CAN_PIN_MAP			CAN_PIN_MAP_PB8_PB9
#else
#error "Invalid Board!"
#endif

#ifdef GD32E10X_H
#define CONFIG_GD32E10X			1
#define FMC_PAGE_SIZE			1024
#endif

#ifdef GD32F10X_H
#define CONFIG_GD32F10X			1

#ifdef GD32F10X_MD
#define FMC_PAGE_SIZE			1024
#else
#define FMC_PAGE_SIZE			2048
#endif
#endif

#define NELEM(a) \
	(sizeof(a) / sizeof((a)[0]))

#define LAST_ELEM(a) \
	((a)[NELEM(a) - 1])

#define KB(value) \
	((value) << 10)

#define MB(value) \
	((value) << 20)

#define SYSTICK_SECONDS(value) \
	(SystemCoreClock * (value))

#define SYSTICK_MSECONDS(value) \
	(SYSTICK_SECONDS(value) / 1000)

#if S600_UART_PRINT
#define println(fmt, args ...) \
	printf(fmt "\r\n", ##args)

#define pr_pos_info() \
	println("%s:%d", __FILE__, __LINE__)
#else
#define println(fmt, args ...)
#define pr_pos_info()
#endif

#define U32(value) \
	((u32) (value))

#define PU32(value) \
	((u32 *) (value))

#define U16(value) \
	((u16) (value))

#define PU16(value) \
	((u16 *) (value))

#define U8(value) \
	((u8) (value))

#define PU8(value) \
	((u8 *) (value))

#define DECODE_U16(buff) \
	(U16(buff[1]) << 8 | buff[0])

#define DECODE_U24(buff) \
	(U32(buff[2]) << 16 | DECODE_U16(buff))

#define DECODE_U32(buff) \
	(U32(buff[3]) << 24 | DECODE_U24(buff))

typedef uint32_t u32;
typedef int32_t s32;

typedef uint16_t u16;
typedef int16_t s16;

typedef uint8_t u8;
typedef int8_t s8;

typedef void (*s600_command_t)(void);

#ifdef CONFIG_GD32E10X
typedef enum {
	false,
	true,
} bool;
#else
#define true TRUE
#define false FALSE
#endif

extern uint32_t SystemCoreClock;
extern const u8 s600_value_char_map[];
extern u32 s600_iap_100ms;

u16 s600_get_avg_value(const u16 *values, u16 size);
u32 s600_checksum_put(u32 checksum, const u8 *data, u16 size);
u32 s600_checksum_put_value(u32 checksum, u16 value);
u16 s600_checksum_finish(u32 checksum);
u8 s600_char2value(char ch);
u8 s600_month2value(const char *text);

u16 s600_decode_u16(const u8 *buff);
u32 s600_decode_u24(const u8 *buff);
u32 s600_decode_u32(const u8 *buff);

void s600_encode_u16(u8 *buff, u16 value);
void s600_encode_u24(u8 *buff, u32 value);
void s600_encode_u32(u8 *buff, u32 value);
