
#define BITS_PER_SUPERFRAME	12672.0	/* super frame (Oberrahmen) has duration of exactly 2.4 seconds */
#define BITS_PER_BLOCK		198.0	/* block has duration of exactly 37.5 milli seconds */
#define BITS_PER_SPK_BLOCK	66.0	/* spk block has a duration of exactly 12.5 milli seconds */

/* fsk rx sync state */
enum fsk_sync {
	FSK_SYNC_NONE = 0,
	FSK_SYNC_POSITIVE,
	FSK_SYNC_NEGATIVE,
};

enum demod_type {
	FSK_DEMOD_AUTO, /* auto selection of the demod type below */
	FSK_DEMOD_SLOPE, /* check for highest slope (good for sound cards) */
	FSK_DEMOD_LEVEL, /* check for zero crossing (good for SDR) */
};

typedef struct fsk_fm_demod {
	cnetz_t		*cnetz;			/* pointer back to cnetz instance */

	/* clock */
	double		bit_time;		/* current time in bits inside superframe */
	double		bit_time_uncorrected;	/* same as above, but not corrected by sync */

	/* bit detection */
	enum demod_type	demod_type;		/* how to demodulate bits */
	sample_t	*bit_buffer_spl;	/* samples ring buffer */
	int		bit_buffer_len;		/* number of samples in ring buffer */
	int		bit_buffer_half;	/* half of ring buffer */
	int		bit_buffer_pos;		/* current position to write next sample */
	double		level_threshold;	/* threshold for detection of next level change */
	double		bits_per_sample;	/* duration of one sample in bits */
	double		next_bit;		/* count time to detect bits */
	int		bit_count;		/* counts bits, to match 4 bits at distributed signaling */
	int		last_change_positive;	/* flags last level change direction */
	enum fsk_sync	sync;			/* set, if we are in sync and what polarity we receive */
	double		sync_level;		/* what was the level, when we received the sync */
	double		sync_time;		/* when did we receive sync, relative to super frame */
	double		sync_stddev;		/* standard deviation of level changes */

	/* speech */
	sample_t	*speech_buffer;		/* holds one chunk of 12.5ms */
	int		speech_size;
	int		speech_count;

	/* bit decoder */
	uint64_t	rx_sync;		/* sync shift register */
	char		rx_buffer[151];		/* 150 bits + termination */
	int		rx_buffer_count;	/* counter when receiving bits */

	/* statistics */
	double		change_levels[256];	/* ring buffer to store levels */
	double		change_when[256];	/* ring buffer to store time when level has changed */
	uint8_t		change_pos;		/* index for next write */

	/* display measurements */
	dispmeasparam_t		*dmp_frame_level;
	dispmeasparam_t		*dmp_frame_stddev;

	/* debug */
	FILE		*debug_fp;		/* file pointer for debugging output */
} fsk_fm_demod_t;

int fsk_fm_init(fsk_fm_demod_t *fsk, cnetz_t *cnetz, int samplerate, double bitrate, enum demod_type);
void fsk_fm_exit(fsk_fm_demod_t *fsk);
void fsk_fm_demod(fsk_fm_demod_t *fsk, sample_t *samples, int length);
void fsk_correct_sync(fsk_fm_demod_t *fsk, double offset);
void fsk_copy_sync(fsk_fm_demod_t *fsk_to, fsk_fm_demod_t *fsk_from);
void fsk_demod_reset(fsk_fm_demod_t *fsk);

